From f718f8e3f47f55283a2b9a397f7fd28be242b3e0 Mon Sep 17 00:00:00 2001 From: Aaron Fiore Date: Wed, 25 Mar 2026 16:30:32 -0700 Subject: [PATCH] container: hledger-flow: coinbase: refactor %created_at timezone --- .../accounts/coinbase/coinbase-shared.bash | 12 ++-- .../accounts/coinbase/coinbase-shared.rules | 64 ++++++++++--------- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/container/src/hledger-flow/accounts/coinbase/coinbase-shared.bash b/container/src/hledger-flow/accounts/coinbase/coinbase-shared.bash index 683a008..bd7a069 100755 --- a/container/src/hledger-flow/accounts/coinbase/coinbase-shared.bash +++ b/container/src/hledger-flow/accounts/coinbase/coinbase-shared.bash @@ -82,10 +82,12 @@ function __parse() sub(/^-/, "", $5) sub(/^-/, "", $7) - # Cleanup timestamp - sub(/T/, " ", $9); - sub(/Z/, "", $9); - sub(/\+.*/, "", $9); + # Prepare info_created_at (NOTE: server returns UTC) + created_at=$9 + sub(/T/, " ", created_at); + sub(/Z/, "", created_at); + sub(/\+.*/, "", created_at); + created_at=created_at " +0000" # Print [info] object for rules consumption printf $1 OFS # account_id (prepended column) @@ -96,7 +98,7 @@ function __parse() printf "\"" $6 "\"" OFS # info_amount_currency printf $7 OFS # info_native_amount_amount printf "\"" $8 "\"" OFS # info_native_amount_currency - printf $9 OFS # info_created_at + printf created_at OFS # info_created_at printf $10 OFS # info_resource printf $11 OFS # info_resource_path printf $12 OFS # info_description diff --git a/container/src/hledger-flow/accounts/coinbase/coinbase-shared.rules b/container/src/hledger-flow/accounts/coinbase/coinbase-shared.rules index 0e248fa..a5721bf 100644 --- a/container/src/hledger-flow/accounts/coinbase/coinbase-shared.rules +++ b/container/src/hledger-flow/accounts/coinbase/coinbase-shared.rules @@ -1,6 +1,6 @@ # docker-finance | modern accounting for the power-user # -# Copyright (C) 2021-2025 Aaron Fiore (Founder, Evergreen Crypto LLC) +# Copyright (C) 2021-2026 Aaron Fiore (Founder, Evergreen Crypto LLC) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -81,13 +81,17 @@ fields account_id,coinbase_id,type,status_,amount_amount,amount_currency,native_ # subaccount date %created_at -date-format %Y-%m-%d %H:%M:%S +date-format %Y-%m-%d %H:%M:%S %z account1 assets:coinbase:%subaccount:%amount_currency amount %amount_amount "%amount_currency" -# NOTE: server time is UTC, as are the timestamps. -description %created_at +0000 +# 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`. +# +description %created_at comment type:%type, status:%status_, account_id:%account_id, coinbase_id:%coinbase_id @@ -164,7 +168,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 +0000,SPEND,coinbase:%subaccount,%network_transaction_fee_currency,%network_transaction_fee_amount,%native_amount_currency,%native_network_transaction_fee_amount,FEE + comment3 %created_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 # @@ -183,14 +187,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 +0000,SPEND,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,Send via email + comment2 %created_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 +0000,SPEND,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,Send to %to_email + comment2 %created_at,SPEND,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,Send to %to_email # TODO: phone number support @@ -276,7 +280,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 +0000,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, + comment2 %created_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, # Crypto Spend @@ -284,7 +288,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 +0000,SPEND,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,Coinbase Card + comment2 %created_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 @@ -307,32 +311,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 +0000,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,REWARD + comment2 %created_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 +0000,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,REWARD + comment2 %created_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 +0000,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,REWARD + comment2 %created_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 +0000,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,INTEREST + comment2 %created_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 +0000,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,STAKING + comment2 %created_at,INCOME,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,STAKING ################################################################################ # # @@ -358,23 +362,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 +0000,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%buy_total_currency,%buy_total_amount,, + comment2 %created_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 +0000,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%buy_total_currency,%buy_total_amount,%buy_fee_currency,%buy_fee_amount + comment2 %created_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 +0000,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%buy_total_currency,%buy_total_amount,, + comment2 %created_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 +0000,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, + comment2 %created_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, if %type ^buy$ & %buy_fee_amount [1-9] @@ -413,23 +417,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 +0000,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%sell_total_currency,%sell_total_amount,, + comment2 %created_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 +0000,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%sell_total_currency,%sell_total_amount,%sell_fee_currency,%sell_fee_amount + comment2 %created_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 +0000,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%sell_total_currency,%sell_total_amount,, + comment2 %created_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 +0000,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, + comment2 %created_at,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, if %type ^sell$ & %sell_fee_amount [1-9] @@ -633,7 +637,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 +0000,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, + comment2 %created_at,SELL,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, if %type ^trade$ & %direction ^OUT$ @@ -649,7 +653,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 +0000,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, + comment2 %created_at,BUY,coinbase:%subaccount,%amount_currency,%amount_amount,%native_amount_currency,%native_amount_amount,, if %type ^trade$ & %direction ^IN$ @@ -707,14 +711,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 +0000,BUY,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, + comment2 %created_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 +0000,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 %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 # 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 @@ -724,7 +728,7 @@ if %type ^advanced_trade_fill$ & %advanced_trade_fill_commission [1-9] & %advanced_trade_fill_pair_rhs ^USD$ & %direction ^IN$ - comment2 %created_at +0000,BUY,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, + comment2 %created_at,BUY,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, # # SELL @@ -743,14 +747,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 +0000,SELL,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, + comment2 %created_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 +0000,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 %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 # 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 @@ -760,6 +764,6 @@ if %type ^advanced_trade_fill$ & %advanced_trade_fill_commission [1-9] & %advanced_trade_fill_pair_rhs ^USD$ & %direction ^OUT$ - comment2 %created_at +0000,SELL,coinbase:%subaccount,%advanced_trade_fill_pair_lhs,%amount_amount,%advanced_trade_fill_pair_rhs,%advanced_trade_fill_cost_basis_amount,, + comment2 %created_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