@@ -175,6 +175,35 @@ def test_transfer_analysis_success_using_multiple_accounts_and_fifo(self) -> Non
175175 },
176176 want_error = "" ,
177177 ),
178+ _Test (
179+ description = "Reciprocal transfer + sales: CB->Kraken, Kraken->CB, CB sales" ,
180+ input = [
181+ InTransactionDescriptor ("1" , 1 , 1 , "Coinbase" , "Bob" , 110 , 10 ),
182+ InTransactionDescriptor ("2" , 2 , 2 , "Kraken" , "Bob" , 120 , 10 ),
183+ IntraTransactionDescriptor ("3" , 3 , 3 , "Coinbase" , "Bob" , "Kraken" , "Bob" , 130 , 4 , 3 ),
184+ IntraTransactionDescriptor ("4" , 4 , 4 , "Kraken" , "Bob" , "Coinbase" , "Bob" , 140 , 2 , 1 ),
185+ OutTransactionDescriptor ("5" , 5 , 5 , "Kraken" , "Bob" , 150 , 2 , 1 ),
186+ OutTransactionDescriptor ("6" , 6 , 6 , "Coinbase" , "Bob" , 150 , 3 , 2 ),
187+ ],
188+ want = {
189+ Account ("Coinbase" , "Bob" ): [
190+ InTransactionDescriptor ("1" , 1 , 1 , "Coinbase" , "Bob" , 110 , 10 , to_lot_unique_ids = {Account ("Kraken" , "Bob" ): ["3/-1" ]}),
191+ IntraTransactionDescriptor ("3" , 3 , 3 , "Coinbase" , "Bob" , "Kraken" , "Bob" , 130 , 4 , 3 ),
192+ OutTransactionDescriptor ("6" , 6 , 6 , "Coinbase" , "Bob" , 150 , 3 , 2 ),
193+ ],
194+ Account ("Kraken" , "Bob" ): [
195+ InTransactionDescriptor ("3/-1" , 3 , - 1 , "Kraken" , "Bob" , 110 , 3 , from_lot_unique_id = "1" , cost_basis_day = 1 ),
196+ InTransactionDescriptor ("2" , 2 , 2 , "Kraken" , "Bob" , 120 , 10 ),
197+ IntraTransactionDescriptor ("4" , 4 , 4 , "Kraken" , "Bob" , "Coinbase" , "Bob" , 140 , 2 , 1 ),
198+ OutTransactionDescriptor ("5" , 5 , 5 , "Kraken" , "Bob" , 150 , 2 , 1 ),
199+ ],
200+ },
201+ want_amounts = {
202+ Account (exchange = 'Coinbase' , holder = 'Bob' ): {'1' : 2 },
203+ Account (exchange = 'Kraken' , holder = 'Bob' ): {'2' : 8 , '3/-1' : 0 },
204+ },
205+ want_error = "" ,
206+ ),
178207 _Test (
179208 description = "Many transactions with loops, sales and self-transfers across three accounts" ,
180209 input = [
@@ -543,6 +572,36 @@ def test_transfer_analysis_success_using_multiple_accounts_and_lifo(self) -> Non
543572 },
544573 want_error = "" ,
545574 ),
575+ _Test (
576+ description = "Reciprocal transfer + sales: CB->Kraken, Kraken->CB, CB sales" ,
577+ input = [
578+ InTransactionDescriptor ("1" , 1 , 1 , "Coinbase" , "Bob" , 110 , 10 ),
579+ InTransactionDescriptor ("2" , 2 , 2 , "Kraken" , "Bob" , 120 , 10 ),
580+ IntraTransactionDescriptor ("3" , 3 , 3 , "Coinbase" , "Bob" , "Kraken" , "Bob" , 130 , 4 , 3 ),
581+ IntraTransactionDescriptor ("4" , 4 , 4 , "Kraken" , "Bob" , "Coinbase" , "Bob" , 140 , 2 , 1 ),
582+ OutTransactionDescriptor ("5" , 5 , 5 , "Kraken" , "Bob" , 150 , 2 , 1 ),
583+ OutTransactionDescriptor ("6" , 6 , 6 , "Coinbase" , "Bob" , 150 , 3 , 2 ),
584+ ],
585+ want = {
586+ Account ("Coinbase" , "Bob" ): [
587+ InTransactionDescriptor ("1" , 1 , 1 , "Coinbase" , "Bob" , 110 , 10 , to_lot_unique_ids = {Account ("Kraken" , "Bob" ): ["3/-1" ]}),
588+ IntraTransactionDescriptor ("3" , 3 , 3 , "Coinbase" , "Bob" , "Kraken" , "Bob" , 130 , 4 , 3 ),
589+ InTransactionDescriptor ("4/-2" , 4 , - 2 , "Coinbase" , "Bob" , 120 , 1 , from_lot_unique_id = "2" , cost_basis_day = 2 ),
590+ OutTransactionDescriptor ("6" , 6 , 6 , "Coinbase" , "Bob" , 150 , 3 , 2 ),
591+ ],
592+ Account ("Kraken" , "Bob" ): [
593+ InTransactionDescriptor ("3/-1" , 3 , - 1 , "Kraken" , "Bob" , 110 , 3 , from_lot_unique_id = "1" , cost_basis_day = 1 ),
594+ InTransactionDescriptor ("2" , 2 , 2 , "Kraken" , "Bob" , 120 , 10 , to_lot_unique_ids = {Account (exchange = 'Coinbase' , holder = 'Bob' ): ["4/-2" ]}),
595+ IntraTransactionDescriptor ("4" , 4 , 4 , "Kraken" , "Bob" , "Coinbase" , "Bob" , 140 , 2 , 1 ),
596+ OutTransactionDescriptor ("5" , 5 , 5 , "Kraken" , "Bob" , 150 , 2 , 1 ),
597+ ],
598+ },
599+ want_amounts = {
600+ Account (exchange = 'Coinbase' , holder = 'Bob' ): {'1' : 2 , '4/-2' : 0 },
601+ Account (exchange = 'Kraken' , holder = 'Bob' ): {'2' : 5 },
602+ },
603+ want_error = "" ,
604+ ),
546605 _Test (
547606 description = "Many transactions with loops, sales and self-transfers across three accounts" ,
548607 input = [
@@ -910,6 +969,36 @@ def test_transfer_analysis_success_using_multiple_accounts_and_hifo(self) -> Non
910969 },
911970 want_error = "" ,
912971 ),
972+ _Test (
973+ description = "Reciprocal transfer + sales: CB->Kraken, Kraken->CB, CB sales" ,
974+ input = [
975+ InTransactionDescriptor ("1" , 1 , 1 , "Coinbase" , "Bob" , 110 , 10 ),
976+ InTransactionDescriptor ("2" , 2 , 2 , "Kraken" , "Bob" , 120 , 10 ),
977+ IntraTransactionDescriptor ("3" , 3 , 3 , "Coinbase" , "Bob" , "Kraken" , "Bob" , 130 , 4 , 3 ),
978+ IntraTransactionDescriptor ("4" , 4 , 4 , "Kraken" , "Bob" , "Coinbase" , "Bob" , 140 , 2 , 1 ),
979+ OutTransactionDescriptor ("5" , 5 , 5 , "Kraken" , "Bob" , 150 , 2 , 1 ),
980+ OutTransactionDescriptor ("6" , 6 , 6 , "Coinbase" , "Bob" , 150 , 3 , 2 ),
981+ ],
982+ want = {
983+ Account ("Coinbase" , "Bob" ): [
984+ InTransactionDescriptor ("1" , 1 , 1 , "Coinbase" , "Bob" , 110 , 10 , to_lot_unique_ids = {Account ("Kraken" , "Bob" ): ["3/-1" ]}),
985+ IntraTransactionDescriptor ("3" , 3 , 3 , "Coinbase" , "Bob" , "Kraken" , "Bob" , 130 , 4 , 3 ),
986+ InTransactionDescriptor ("4/-2" , 4 , - 2 , "Coinbase" , "Bob" , 120 , 1 , from_lot_unique_id = "2" , cost_basis_day = 2 ),
987+ OutTransactionDescriptor ("6" , 6 , 6 , "Coinbase" , "Bob" , 150 , 3 , 2 ),
988+ ],
989+ Account ("Kraken" , "Bob" ): [
990+ InTransactionDescriptor ("3/-1" , 3 , - 1 , "Kraken" , "Bob" , 110 , 3 , from_lot_unique_id = "1" , cost_basis_day = 1 ),
991+ InTransactionDescriptor ("2" , 2 , 2 , "Kraken" , "Bob" , 120 , 10 , to_lot_unique_ids = {Account (exchange = 'Coinbase' , holder = 'Bob' ): ["4/-2" ]}),
992+ IntraTransactionDescriptor ("4" , 4 , 4 , "Kraken" , "Bob" , "Coinbase" , "Bob" , 140 , 2 , 1 ),
993+ OutTransactionDescriptor ("5" , 5 , 5 , "Kraken" , "Bob" , 150 , 2 , 1 ),
994+ ],
995+ },
996+ want_amounts = {
997+ Account (exchange = 'Coinbase' , holder = 'Bob' ): {'1' : 2 , '4/-2' : 0 },
998+ Account (exchange = 'Kraken' , holder = 'Bob' ): {'2' : 5 },
999+ },
1000+ want_error = "" ,
1001+ ),
9131002 _Test (
9141003 description = "Many transactions with loops, sales and self-transfers across three accounts" ,
9151004 input = [
@@ -1280,6 +1369,35 @@ def test_transfer_analysis_success_using_multiple_accounts_and_lofo(self) -> Non
12801369 },
12811370 want_error = "" ,
12821371 ),
1372+ _Test (
1373+ description = "Reciprocal transfer + sales: CB->Kraken, Kraken->CB, CB sales" ,
1374+ input = [
1375+ InTransactionDescriptor ("1" , 1 , 1 , "Coinbase" , "Bob" , 110 , 10 ),
1376+ InTransactionDescriptor ("2" , 2 , 2 , "Kraken" , "Bob" , 120 , 10 ),
1377+ IntraTransactionDescriptor ("3" , 3 , 3 , "Coinbase" , "Bob" , "Kraken" , "Bob" , 130 , 4 , 3 ),
1378+ IntraTransactionDescriptor ("4" , 4 , 4 , "Kraken" , "Bob" , "Coinbase" , "Bob" , 140 , 2 , 1 ),
1379+ OutTransactionDescriptor ("5" , 5 , 5 , "Kraken" , "Bob" , 150 , 2 , 1 ),
1380+ OutTransactionDescriptor ("6" , 6 , 6 , "Coinbase" , "Bob" , 150 , 3 , 2 ),
1381+ ],
1382+ want = {
1383+ Account ("Coinbase" , "Bob" ): [
1384+ InTransactionDescriptor ("1" , 1 , 1 , "Coinbase" , "Bob" , 110 , 10 , to_lot_unique_ids = {Account ("Kraken" , "Bob" ): ["3/-1" ]}),
1385+ IntraTransactionDescriptor ("3" , 3 , 3 , "Coinbase" , "Bob" , "Kraken" , "Bob" , 130 , 4 , 3 ),
1386+ OutTransactionDescriptor ("6" , 6 , 6 , "Coinbase" , "Bob" , 150 , 3 , 2 ),
1387+ ],
1388+ Account ("Kraken" , "Bob" ): [
1389+ InTransactionDescriptor ("3/-1" , 3 , - 1 , "Kraken" , "Bob" , 110 , 3 , from_lot_unique_id = "1" , cost_basis_day = 1 ),
1390+ InTransactionDescriptor ("2" , 2 , 2 , "Kraken" , "Bob" , 120 , 10 ),
1391+ IntraTransactionDescriptor ("4" , 4 , 4 , "Kraken" , "Bob" , "Coinbase" , "Bob" , 140 , 2 , 1 ),
1392+ OutTransactionDescriptor ("5" , 5 , 5 , "Kraken" , "Bob" , 150 , 2 , 1 ),
1393+ ],
1394+ },
1395+ want_amounts = {
1396+ Account (exchange = 'Coinbase' , holder = 'Bob' ): {'1' : 2 },
1397+ Account (exchange = 'Kraken' , holder = 'Bob' ): {'2' : 8 , '3/-1' : 0 },
1398+ },
1399+ want_error = "" ,
1400+ ),
12831401 _Test (
12841402 description = "Many transactions with loops and self-transfers across three accounts" ,
12851403 input = [
0 commit comments