diff --git a/container/src/hledger-flow/accounts/coinbase/coinbase-shared.bash b/container/src/hledger-flow/accounts/coinbase/coinbase-shared.bash index bd7a069..890054d 100755 --- a/container/src/hledger-flow/accounts/coinbase/coinbase-shared.bash +++ b/container/src/hledger-flow/accounts/coinbase/coinbase-shared.bash @@ -212,6 +212,25 @@ function __parse() cost_basis=(direction ~ /^IN$/ ? real_value_amount + $50 : real_value_amount) printf("%.8f", cost_basis); printf OFS # advanced_trade_fill_cost_basis_amount + # + # 1099-DA (2025+): Since Coinbase uses Eastern Time for tax reporting, and + # %created_at returns UTC, %taxed_at (and form 8949) must align with 1099-DA. + # + + # Only convert for years 2025+ + cmd = "TZ=\"US/Eastern\" date \"+%F %T %z\" --date="$9 | getline date + split(date, year, "-"); + if (year[1] <= 2024) + { + cmd = "TZ=\"UTC\" date \"+%F %T %z\" --date="$9 | getline date + } + taxed_at = date + printf taxed_at OFS + + # + # Remaining defaults + # + printf direction OFS printf global_subaccount diff --git a/container/src/hledger-flow/accounts/coinbase/coinbase-shared.rules b/container/src/hledger-flow/accounts/coinbase/coinbase-shared.rules index a5721bf..3c83029 100644 --- a/container/src/hledger-flow/accounts/coinbase/coinbase-shared.rules +++ b/container/src/hledger-flow/accounts/coinbase/coinbase-shared.rules @@ -15,7 +15,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -fields account_id,coinbase_id,type,status_,amount_amount,amount_currency,native_amount_amount,native_amount_currency,created_at,resource,resource_path,description,network_status,network_network_name,network_hash,network_transaction_fee_amount,network_transaction_fee_currency,to_resource,to_address,to_email,from_resource,from_resource_path,from_id,from_name,cancelable,idem,buy_total_amount,buy_total_currency,buy_subtotal_amount,buy_subtotal_currency,buy_fee_amount,buy_fee_currency,buy_id,buy_payment_method_name,sell_total_amount,sell_total_currency,sell_subtotal_amount,sell_subtotal_currency,sell_fee_amount,sell_fee_currency,sell_id,sell_payment_method_name,trade_fee_amount,trade_fee_currency,trade_id,trade_payment_method_name,advanced_trade_fill_fill_price,advanced_trade_fill_product_id,advanced_trade_fill_order_id,advanced_trade_fill_commission,advanced_trade_fill_order_side,native_amount_price,native_network_transaction_fee_amount,network_transaction_amount_amount,advanced_trade_fill_real_value_amount,advanced_trade_fill_pair_lhs,advanced_trade_fill_pair_rhs,advanced_trade_fill_cost_basis_amount,direction,subaccount +fields account_id,coinbase_id,type,status_,amount_amount,amount_currency,native_amount_amount,native_amount_currency,created_at,resource,resource_path,description,network_status,network_network_name,network_hash,network_transaction_fee_amount,network_transaction_fee_currency,to_resource,to_address,to_email,from_resource,from_resource_path,from_id,from_name,cancelable,idem,buy_total_amount,buy_total_currency,buy_subtotal_amount,buy_subtotal_currency,buy_fee_amount,buy_fee_currency,buy_id,buy_payment_method_name,sell_total_amount,sell_total_currency,sell_subtotal_amount,sell_subtotal_currency,sell_fee_amount,sell_fee_currency,sell_id,sell_payment_method_name,trade_fee_amount,trade_fee_currency,trade_id,trade_payment_method_name,advanced_trade_fill_fill_price,advanced_trade_fill_product_id,advanced_trade_fill_order_id,advanced_trade_fill_commission,advanced_trade_fill_order_side,native_amount_price,native_network_transaction_fee_amount,network_transaction_amount_amount,advanced_trade_fill_real_value_amount,advanced_trade_fill_pair_lhs,advanced_trade_fill_pair_rhs,advanced_trade_fill_cost_basis_amount,taxed_at,direction,subaccount # The above fields; in order and in human-readable form: # @@ -77,6 +77,7 @@ fields account_id,coinbase_id,type,status_,amount_amount,amount_currency,native_ # advanced_trade_fill_pair_lhs # advanced_trade_fill_pair_rhs # advanced_trade_fill_cost_basis_amount +# taxed_at # direction # subaccount @@ -89,7 +90,9 @@ amount %amount_amount "%amount_currency" # NOTE: # # - Server time is UTC, as are the timestamps. However, their generated 1099-DA is ET (Eastern Time). -# - TODO: For disposal-related taxable events, use %taxed_at timestamp in tx comment for `taxes`. +# +# - For disposal-related taxable events, use %taxed_at timestamp in tx comment for `taxes`. +# * For years 2025+, the %taxed_at time (ET) will be converted from %created_at (UTC). # description %created_at @@ -168,7 +171,7 @@ if %type ^send$ account4 expenses:coinbase:%subaccount:fees:send:%native_amount_currency amount4 %native_network_transaction_fee_amount %native_amount_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, idem:%idem, network_status:%network_status, network_name:%network_network_name, to_address:%to_address, txid:%network_hash, direction:%direction, taxed_as:SPEND - comment3 %created_at,SPEND,coinbase:%subaccount,%network_transaction_fee_currency,%network_transaction_fee_amount,%native_amount_currency,%native_network_transaction_fee_amount,FEE + comment3 %taxed_at,SPEND,coinbase:%subaccount,%network_transaction_fee_currency,%network_transaction_fee_amount,%native_amount_currency,%native_network_transaction_fee_amount,FEE # Marked as comment3 in case user-defined rules use comment2 to SPEND/GIFT the non-fee amount # @@ -187,14 +190,14 @@ if %type ^send$ & %to_resource ^email$ account2 expenses:coinbase:%subaccount:send_email:%amount_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, idem:%idem, network_status:%network_status, to_resource:%to_resource, direction:%direction, taxed_as:SPEND - comment2 %created_at,SPEND,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,Send via email + comment2 %taxed_at,SPEND,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,Send via email if %type ^send$ & %direction ^OUT$ & %to_resource ^email$ & %to_email [a-z] comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, idem:%idem, network_status:%network_status, to_resource:%to_resource, to_email:%to_email, direction:%direction, taxed_as:SPEND - comment2 %created_at,SPEND,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,Send to %to_email + comment2 %taxed_at,SPEND,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,Send to %to_email # TODO: phone number support @@ -280,7 +283,7 @@ if %type ^send$ amount %amount_amount "%amount_currency" @@ %native_amount_amount %native_amount_currency account2 income:coinbase:%subaccount:card:%native_amount_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, taxed_as:REBATE - comment2 %created_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, + comment2 %taxed_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, # Crypto Spend @@ -288,7 +291,7 @@ if %type ^cardspend$ amount -%amount_amount "%amount_currency" @@ %native_amount_amount %native_amount_currency account2 expenses:coinbase:%subaccount:card:%amount_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, taxed_as:SPEND - comment2 %created_at,SPEND,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,Coinbase Card + comment2 %taxed_at,SPEND,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,Coinbase Card # Cash Spend (Native Fiat Wallet) # TODO: any reference to USD should be a backreferenced %native_amount_currency @@ -311,32 +314,32 @@ if %type ^send$ & %from_name ^Coinbase Earn$ account2 income:coinbase:%subaccount:earn:%amount_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, taxed_as:INCOME - comment2 %created_at,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,REWARD + comment2 %taxed_at,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,REWARD if %type ^earn_payout$ account2 income:coinbase:%subaccount:earn:%amount_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, taxed_as:INCOME - comment2 %created_at,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,REWARD + comment2 %taxed_at,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,REWARD if %type ^tx$ & %description ^Earn Task$ account2 income:coinbase:%subaccount:earn:%amount_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, taxed_as:INCOME - comment2 %created_at,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,REWARD + comment2 %taxed_at,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,REWARD # Interest if %type ^interest$ account2 income:coinbase:%subaccount:interest:%amount_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, taxed_as:INCOME - comment2 %created_at,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,INTEREST + comment2 %taxed_at,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,INTEREST # Staking if %type (^inflation_reward$|^staking_reward$) account2 income:coinbase:%subaccount:staking:%amount_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, taxed_as:INCOME - comment2 %created_at,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,STAKING + comment2 %taxed_at,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,STAKING ################################################################################ # # @@ -362,23 +365,23 @@ if %type ^buy$ amount %amount_amount "%amount_currency" @@ %buy_total_amount "%buy_total_currency" account2 assets:coinbase:%subaccount:%buy_total_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, buy_id:%buy_id, taxed_as:BUY - comment2 %created_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%buy_total_currency,%buy_total_amount,, + comment2 %taxed_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%buy_total_currency,%buy_total_amount,, if %type ^buy$ & %buy_fee_amount [1-9] - comment2 %created_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%buy_total_currency,%buy_total_amount,%buy_fee_currency,%buy_fee_amount + comment2 %taxed_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%buy_total_currency,%buy_total_amount,%buy_fee_currency,%buy_fee_amount # TODO: HACK: re: #51, FeeCurrency and Fee are added even though cost-basis is calculated (for non-fiat fee disposal, see lib_taxes) # TODO: HACK: see #51 and respective lib_taxes work-around if %type ^buy$ & %buy_fee_amount [1-9] & %buy_fee_currency ^USD$ - comment2 %created_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%buy_total_currency,%buy_total_amount,, + comment2 %taxed_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%buy_total_currency,%buy_total_amount,, if %type ^buy$ & %buy_total_currency ^USDC$ amount %amount_amount "%amount_currency" @@ %native_amount_amount %native_amount_currency - comment2 %created_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, + comment2 %taxed_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, if %type ^buy$ & %buy_fee_amount [1-9] @@ -417,23 +420,23 @@ if %type ^sell$ amount -%amount_amount "%amount_currency" @@ %sell_total_amount "%sell_total_currency" account2 assets:coinbase:%subaccount:%sell_total_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, sell_id:%sell_id, taxed_as:SELL - comment2 %created_at,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%sell_total_currency,%sell_total_amount,, + comment2 %taxed_at,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%sell_total_currency,%sell_total_amount,, if %type ^sell$ & %sell_fee_amount [1-9] - comment2 %created_at,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%sell_total_currency,%sell_total_amount,%sell_fee_currency,%sell_fee_amount + comment2 %taxed_at,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%sell_total_currency,%sell_total_amount,%sell_fee_currency,%sell_fee_amount # TODO: HACK: re: #51, FeeCurrency and Fee are added even though cost-basis is calculated (for non-fiat fee disposal, see lib_taxes) # TODO: HACK: see #51 and respective lib_taxes work-around if %type ^sell$ & %sell_fee_amount [1-9] & %sell_fee_currency ^USD$ - comment2 %created_at,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%sell_total_currency,%sell_total_amount,, + comment2 %taxed_at,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%sell_total_currency,%sell_total_amount,, if %type ^sell$ & %sell_total_currency ^USDC$ amount -%amount_amount %amount_currency @@ %native_amount_amount %native_amount_currency - comment2 %created_at,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, + comment2 %taxed_at,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, if %type ^sell$ & %sell_fee_amount [1-9] @@ -637,7 +640,7 @@ if %type ^trade$ amount -%amount_amount "%amount_currency" @@ %native_amount_amount %native_amount_currency account2 equity:coinbase:%subaccount:conversion:%native_amount_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, taxed_as:SELL - comment2 %created_at,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, + comment2 %taxed_at,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, if %type ^trade$ & %direction ^OUT$ @@ -653,7 +656,7 @@ if %type ^trade$ amount %amount_amount "%amount_currency" @@ %native_amount_amount %native_amount_currency account2 equity:coinbase:%subaccount:conversion:%native_amount_currency comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, taxed_as:BUY - comment2 %created_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, + comment2 %taxed_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, if %type ^trade$ & %direction ^IN$ @@ -711,14 +714,14 @@ if %type ^advanced_trade_fill$ & %direction ^IN$ amount %amount_amount "%advanced_trade_fill_pair_lhs" @@ %advanced_trade_fill_real_value_amount "%advanced_trade_fill_pair_rhs" comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, advanced_trade_fill_fill_price:%advanced_trade_fill_fill_price, advanced_trade_fill_product_id:%advanced_trade_fill_product_id, advanced_trade_fill_order_id:%advanced_trade_fill_order_id, advanced_trade_fill_order_side:%advanced_trade_fill_order_side, advanced_trade_fill_pair_lhs:%advanced_trade_fill_pair_lhs, advanced_trade_fill_pair_rhs:%advanced_trade_fill_pair_rhs, direction:%direction, taxed_as:BUY - comment2 %created_at,BUY,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, + comment2 %taxed_at,BUY,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, if %type ^advanced_trade_fill$ & %advanced_trade_fill_order_side ^buy$ & %advanced_trade_fill_real_value_amount [1-9] & %advanced_trade_fill_commission [1-9] & %direction ^IN$ - comment2 %created_at,BUY,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_commission + comment2 %taxed_at,BUY,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_commission # TODO: HACK: re: #51, FeeCurrency and Fee are added even though cost-basis is calculated (for non-fiat fee disposal, see lib_taxes) # TODO: HACK: see #51 and respective lib_taxes work-around @@ -728,7 +731,7 @@ if %type ^advanced_trade_fill$ & %advanced_trade_fill_commission [1-9] & %advanced_trade_fill_pair_rhs ^USD$ & %direction ^IN$ - comment2 %created_at,BUY,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, + comment2 %taxed_at,BUY,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, # # SELL @@ -747,14 +750,14 @@ if %type ^advanced_trade_fill$ & %direction ^OUT$ amount -%amount_amount "%advanced_trade_fill_pair_lhs" @@ %advanced_trade_fill_real_value_amount "%advanced_trade_fill_pair_rhs" comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id, advanced_trade_fill_fill_price:%advanced_trade_fill_fill_price, advanced_trade_fill_product_id:%advanced_trade_fill_product_id, advanced_trade_fill_order_id:%advanced_trade_fill_order_id, advanced_trade_fill_order_side:%advanced_trade_fill_order_side, advanced_trade_fill_pair_lhs:%advanced_trade_fill_pair_lhs, advanced_trade_fill_pair_rhs:%advanced_trade_fill_pair_rhs, direction:%direction, taxed_as:SELL - comment2 %created_at,SELL,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, + comment2 %taxed_at,SELL,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, if %type ^advanced_trade_fill$ & %advanced_trade_fill_order_side ^sell$ & %advanced_trade_fill_real_value_amount [1-9] & %advanced_trade_fill_commission [1-9] & %direction ^OUT$ - comment2 %created_at,SELL,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_commission + comment2 %taxed_at,SELL,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_commission # TODO: HACK: re: #51, FeeCurrency and Fee are added even though cost-basis is calculated (for non-fiat fee disposal, see lib_taxes) # TODO: HACK: see #51 and respective lib_taxes work-around @@ -764,6 +767,6 @@ if %type ^advanced_trade_fill$ & %advanced_trade_fill_commission [1-9] & %advanced_trade_fill_pair_rhs ^USD$ & %direction ^OUT$ - comment2 %created_at,SELL,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, + comment2 %taxed_at,SELL,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, # vim: sw=2 sts=2 si ai et