示例#1
0
    def add_loan_gain(self, gained_asset, gained_amount, fee_in_asset,
                      lent_amount, open_time, close_time):

        timestamp = close_time
        rate = self.get_rate_in_profit_currency(gained_asset, timestamp)

        if gained_asset not in self.events:
            self.events[gained_asset] = Events(list(), list())

        net_gain_amount = gained_amount - fee_in_asset
        gain_in_profit_currency = net_gain_amount * rate
        assert gain_in_profit_currency > 0, "Loan profit is negative. Should never happen"
        self.events[gained_asset].buys.append(
            BuyEvent(amount=net_gain_amount,
                     timestamp=timestamp,
                     rate=rate,
                     fee_rate=0,
                     cost=0))
        # count profits if we are inside the query period
        if timestamp >= self.query_start_ts:
            self.loan_profit += gain_in_profit_currency

            self.csv_exporter.add_loan_profit(
                gained_asset=gained_asset,
                gained_amount=gained_amount,
                gain_in_profit_currency=gain_in_profit_currency,
                lent_amount=lent_amount,
                open_time=open_time,
                close_time=close_time,
            )
示例#2
0
    def add_margin_position(self, gained_asset, gained_amount, fee_in_asset,
                            margin_notes, timestamp):

        rate = self.get_rate_in_profit_currency(gained_asset, timestamp)

        if gained_asset not in self.events:
            self.events[gained_asset] = Events(list(), list())

        net_gain_amount = gained_amount - fee_in_asset
        gain_in_profit_currency = net_gain_amount * rate
        assert gain_in_profit_currency > 0, (
            'Margin profit is negative. Should never happen for the hacky way I use em now'
        )
        self.events[gained_asset].buys.append(
            BuyEvent(amount=net_gain_amount,
                     timestamp=timestamp,
                     rate=rate,
                     fee_rate=0,
                     cost=0))
        # count profits if we are inside the query period
        if timestamp >= self.query_start_ts:
            self.margin_positions_profit += gain_in_profit_currency

        self.csv_exporter.add_margin_position(
            margin_notes=margin_notes,
            gained_asset=gained_asset,
            net_gain_amount=net_gain_amount,
            gain_in_profit_currency=gain_in_profit_currency,
            timestamp=timestamp,
        )
示例#3
0
    def add_buy(self,
                bought_asset,
                bought_amount,
                paid_with_asset,
                trade_rate,
                trade_fee,
                fee_currency,
                timestamp,
                is_virtual=False):

        paid_with_asset_rate = self.get_rate_in_profit_currency(
            paid_with_asset, timestamp)
        buy_rate = paid_with_asset_rate * trade_rate
        fee_price_in_profit_currency = 0
        if trade_fee != 0:
            fee_price_in_profit_currency = self.price_historian.query_historical_price(
                fee_currency, self.profit_currency, timestamp)

        self.handle_prefork_acquisitions(bought_asset=bought_asset,
                                         bought_amount=bought_amount,
                                         paid_with_asset=paid_with_asset,
                                         trade_rate=trade_rate,
                                         trade_fee=trade_fee,
                                         fee_currency=fee_currency,
                                         timestamp=timestamp)

        if bought_asset not in self.events:
            self.events[bought_asset] = Events(list(), list())

        fee_cost = fee_price_in_profit_currency * trade_fee
        gross_cost = bought_amount * buy_rate
        cost = gross_cost + fee_cost

        self.events[bought_asset].buys.append(
            BuyEvent(amount=bought_amount,
                     timestamp=timestamp,
                     rate=buy_rate,
                     fee_rate=fee_cost / bought_amount,
                     cost=cost))
        if logger.isEnabledFor(logging.DEBUG):
            logger.debug(
                'Buying {} "{}" for {} "{}" ({} "{}" per "{}" or {} "{}" per '
                '"{}") at {}'.format(
                    bought_amount, bought_asset, bought_amount * trade_rate,
                    paid_with_asset, trade_rate, paid_with_asset, bought_asset,
                    buy_rate, self.profit_currency, bought_asset,
                    tsToDate(timestamp, formatstr='%d/%m/%Y %H:%M:%S')))

        self.csv_exporter.add_buy(
            bought_asset=bought_asset,
            rate=buy_rate,
            fee_cost=fee_cost,
            amount=bought_amount,
            gross_cost=gross_cost,
            cost=cost,
            paid_with_asset=paid_with_asset,
            paid_with_asset_rate=paid_with_asset_rate,
            timestamp=timestamp,
            is_virtual=is_virtual,
        )
def test_reduce_asset_amount(accountant):
    asset = 'BTC'
    events = accountant.events.events
    events[asset] = Events(list(), list())
    events[asset].buys.append(
        BuyEvent(
            amount=FVal(1),
            timestamp=1446979735,  # 08/11/2015
            rate=FVal(268.1),
            fee_rate=FVal(0.0001),
        ),
    )
    events['BTC'].buys.append(
        BuyEvent(
            amount=FVal(1),
            timestamp=1467378304,  # 31/06/2016
            rate=FVal(612.45),
            fee_rate=FVal(0.0019),
        ),
    )
    events['BTC'].buys.append(
        BuyEvent(
            amount=FVal(3),  # 25/10/2016
            timestamp=1477378304,
            rate=FVal(603.415),
            fee_rate=FVal(0.0017),
        ),
    )

    assert accountant.events.reduce_asset_amount(asset, FVal(1.5))
    assert (len(accountant.events.events[asset].buys)) == 2, '1 buy should be used'
    remaining_amount = accountant.events.events[asset].buys[0].amount
    assert remaining_amount == FVal(0.5), '0.5 of 2nd buy should remain'
def test_search_buys_calculate_profit_1_buy_consumed_by_1_sell(accountant):
    """ Assert bought_cost is correct when 1 buy is completely consumed by 1 sell

    Regression test for part of https://github.com/rotkehlchenio/rotkehlchen/issues/223
    """
    asset = 'BTC'
    events = accountant.events.events
    events[asset] = Events(list(), list())
    events[asset].buys.append(
        BuyEvent(
            amount=FVal(5),
            timestamp=1446979735,  # 08/11/2015
            rate=FVal(268.1),
            fee_rate=FVal(0.0001),
        ),
    )

    (
        taxable_amount,
        taxable_bought_cost,
        taxfree_bought_cost,
    ) = accountant.events.search_buys_calculate_profit(
        selling_amount=FVal(5),
        selling_asset=asset,
        timestamp=1467378304,  # 31/06/2016
    )
    assert taxable_amount == 5, '5 out of 5 should be taxable (within a year)'
    assert taxfree_bought_cost.is_close(FVal('0'))
    assert taxable_bought_cost.is_close(FVal('1340.5005'))

    assert (len(accountant.events.events[asset].buys)) == 0, 'only buy should have been used'
示例#6
0
    def add_margin_position(
        self,
        gain_loss_asset: Asset,
        gain_loss_amount: FVal,
        fee_in_asset: Fee,
        margin_notes: str,
        timestamp: Timestamp,
    ) -> None:

        rate = self.get_rate_in_profit_currency(gain_loss_asset, timestamp)

        if gain_loss_asset not in self.events:
            self.events[gain_loss_asset] = Events(list(), list())

        net_gain_loss_amount = gain_loss_amount - fee_in_asset
        gain_loss_in_profit_currency = net_gain_loss_amount * rate

        if net_gain_loss_amount > 0:
            self.events[gain_loss_asset].buys.append(
                BuyEvent(
                    amount=net_gain_loss_amount,
                    timestamp=timestamp,
                    rate=rate,
                    fee_rate=ZERO,
                ), )
        elif net_gain_loss_amount < 0:
            result = self.reduce_asset_amount(
                asset=gain_loss_asset,
                amount=-gain_loss_amount,
            )
            if not result:
                log.critical(
                    f'No documented buy found for {gain_loss_asset} before '
                    f'{timestamp_to_date(timestamp, formatstr="%d/%m/%Y %H:%M:%S")}',
                )

        # count profit/loss if we are inside the query period
        if timestamp >= self.query_start_ts:
            self.margin_positions_profit_loss += gain_loss_in_profit_currency

            log.debug(
                'Accounting for margin position',
                sensitive_log=True,
                notes=margin_notes,
                gain_loss_asset=gain_loss_asset,
                net_gain_loss_amount=net_gain_loss_amount,
                gain_loss_in_profit_currency=gain_loss_in_profit_currency,
                timestamp=timestamp,
            )

            self.csv_exporter.add_margin_position(
                margin_notes=margin_notes,
                gain_loss_asset=gain_loss_asset,
                net_gain_loss_amount=net_gain_loss_amount,
                gain_loss_in_profit_currency=gain_loss_in_profit_currency,
                timestamp=timestamp,
            )
def test_search_buys_calculate_profit_1_buy_used_by_2_sells_taxable(accountant):
    """ Make sure that when 1 buy is used by 2 sells bought cost is correct

    Regression test for taxable part of:
    https://github.com/rotkehlchenio/rotkehlchen/issues/223
    """
    asset = 'BTC'
    events = accountant.events.events
    events[asset] = Events(list(), list())
    events[asset].buys.append(
        BuyEvent(
            amount=FVal(5),
            timestamp=1446979735,  # 08/11/2015
            rate=FVal(268.1),
            fee_rate=FVal(0.0001),
        ),
    )

    (
        taxable_amount,
        taxable_bought_cost,
        taxfree_bought_cost,
    ) = accountant.events.search_buys_calculate_profit(
        selling_amount=FVal(3),
        selling_asset=asset,
        timestamp=1467378304,  # 31/06/2016
    )
    assert taxable_amount == 3, '3 out of 3 should be taxable (within a year)'
    assert taxfree_bought_cost.is_close(FVal('0'))
    assert taxable_bought_cost.is_close(FVal('804.3003'))

    assert (len(accountant.events.events[asset].buys)) == 1, 'whole buy was not used'
    remaining_amount = accountant.events.events[asset].buys[0].amount
    assert remaining_amount == FVal(2), '3 of 5 should have been consumed'

    # now eat up all the rest
    (
        taxable_amount,
        taxable_bought_cost,
        taxfree_bought_cost,
    ) = accountant.events.search_buys_calculate_profit(
        selling_amount=FVal(2),
        selling_asset=asset,
        timestamp=1467378404,  # bit after previous sell
    )
    assert taxable_amount == 2, '2 out of 2 should be taxable (within a year)'
    assert taxfree_bought_cost.is_close(FVal('0'))
    assert taxable_bought_cost.is_close(FVal('536.2002'))

    assert (len(accountant.events.events[asset].buys)) == 0, 'the buy should have been used'
示例#8
0
    def add_loan_gain(
        self,
        gained_asset: Asset,
        gained_amount: FVal,
        fee_in_asset: Fee,
        lent_amount: FVal,
        open_time: Timestamp,
        close_time: Timestamp,
    ) -> None:

        timestamp = close_time
        rate = self.get_rate_in_profit_currency(gained_asset, timestamp)

        if gained_asset not in self.events:
            self.events[gained_asset] = Events(list(), list())

        net_gain_amount = gained_amount - fee_in_asset
        gain_in_profit_currency = net_gain_amount * rate
        assert gain_in_profit_currency > 0, "Loan profit is negative. Should never happen"
        self.events[gained_asset].buys.append(
            BuyEvent(
                amount=net_gain_amount,
                timestamp=timestamp,
                rate=rate,
                fee_rate=ZERO,
            ), )
        # count profits if we are inside the query period
        if timestamp >= self.query_start_ts:
            log.debug(
                'Accounting for loan profit',
                sensitive_log=True,
                gained_asset=gained_asset,
                gained_amount=gained_amount,
                gain_in_profit_currency=gain_in_profit_currency,
                lent_amount=lent_amount,
                open_time=open_time,
                close_time=close_time,
            )

            self.loan_profit += gain_in_profit_currency
            self.csv_exporter.add_loan_profit(
                gained_asset=gained_asset,
                gained_amount=gained_amount,
                gain_in_profit_currency=gain_in_profit_currency,
                lent_amount=lent_amount,
                open_time=open_time,
                close_time=close_time,
            )
def test_search_buys_calculate_profit_after_year(accountant):
    asset = 'BTC'
    events = accountant.events.events
    events[asset] = Events(list(), list())
    events[asset].buys.append(
        BuyEvent(
            amount=FVal(5),
            timestamp=1446979735,  # 08/11/2015
            rate=FVal(268.1),
            fee_rate=FVal(0.0001),
        ),
    )
    events['BTC'].buys.append(
        BuyEvent(
            amount=FVal(15),
            timestamp=1467378304,  # 31/06/2016
            rate=FVal(612.45),
            fee_rate=FVal(0.0019),
        ),
    )
    events['BTC'].buys.append(
        BuyEvent(
            amount=FVal(3),  # 25/10/2016
            timestamp=1477378304,
            rate=FVal(603.415),
            fee_rate=FVal(0.0017),
        ),
    )

    (
        taxable_amount,
        taxable_bought_cost,
        taxfree_bought_cost,
    ) = accountant.events.search_buys_calculate_profit(
        selling_amount=FVal(8),
        selling_asset=asset,
        timestamp=1480683904,  # 02/12/2016
    )

    assert taxable_amount == 3, '3 out of 8 should be taxable (within a year)'
    assert taxfree_bought_cost.is_close(FVal('1340.5005'))
    assert taxable_bought_cost.is_close(FVal('1837.3557'))

    assert (len(accountant.events.events[asset].buys)) == 2, 'first buy should have been used'
    remaining_amount = accountant.events.events[asset].buys[0].amount
    assert remaining_amount == FVal(12), '3 of 15 should have been consumed'
示例#10
0
    def add_margin_position(
        self,
        gain_loss_asset: Asset,
        gain_loss_amount: FVal,
        fee_in_asset: FVal,
        margin_notes: str,
        timestamp: Timestamp,
    ):

        rate = self.get_rate_in_profit_currency(gain_loss_asset, timestamp)

        if gain_loss_asset not in self.events:
            self.events[gain_loss_asset] = Events(list(), list())

        net_gain_loss_amount = gain_loss_amount - fee_in_asset
        gain_loss_in_profit_currency = net_gain_loss_amount * rate

        if net_gain_loss_amount > 0:
            self.events[gain_loss_asset].buys.append(
                BuyEvent(amount=net_gain_loss_amount,
                         timestamp=timestamp,
                         rate=rate,
                         fee_rate=0,
                         cost=0))
        # count profit/loss if we are inside the query period
        if timestamp >= self.query_start_ts:
            self.margin_positions_profit_loss += gain_loss_in_profit_currency

            log.debug(
                'Accounting for margin position',
                sensitive_log=True,
                notes=margin_notes,
                gain_loss_asset=gain_loss_asset,
                net_gain_loss_amount=net_gain_loss_amount,
                gain_loss_in_profit_currency=gain_loss_in_profit_currency,
                timestamp=timestamp,
            )

            self.csv_exporter.add_margin_position(
                margin_notes=margin_notes,
                gain_loss_asset=gain_loss_asset,
                net_gain_loss_amount=net_gain_loss_amount,
                gain_loss_in_profit_currency=gain_loss_in_profit_currency,
                timestamp=timestamp,
            )
def test_reduce_asset_amount_more_that_bought(accountant):
    asset = 'BTC'
    events = accountant.events.events
    events[asset] = Events(list(), list())
    events[asset].buys.append(
        BuyEvent(
            amount=FVal(1),
            timestamp=1446979735,  # 08/11/2015
            rate=FVal(268.1),
            fee_rate=FVal(0.0001),
        ),
    )
    events['BTC'].buys.append(
        BuyEvent(
            amount=FVal(1),
            timestamp=1467378304,  # 31/06/2016
            rate=FVal(612.45),
            fee_rate=FVal(0.0019),
        ),
    )

    assert not accountant.events.reduce_asset_amount(asset, FVal(3))
    assert (len(accountant.events.events[asset].buys)) == 0, 'all buys should be used'
def test_search_buys_calculate_profit_sell_more_than_bought_after_year(accountant):
    asset = 'BTC'
    events = accountant.events.events
    events[asset] = Events(list(), list())
    events[asset].buys.append(
        BuyEvent(
            amount=FVal(1),
            timestamp=1446979735,  # 08/11/2015
            rate=FVal(268.1),
            fee_rate=FVal(0.0001),
        ),
    )
    events['BTC'].buys.append(
        BuyEvent(
            amount=FVal(1),
            timestamp=1467378304,  # 31/06/2016
            rate=FVal(612.45),
            fee_rate=FVal(0.0019),
        ),
    )

    (
        taxable_amount,
        taxable_bought_cost,
        taxfree_bought_cost,
    ) = accountant.events.search_buys_calculate_profit(
        selling_amount=FVal(3),
        selling_asset=asset,
        timestamp=1523399409,  # 10/04/2018
    )

    assert taxable_amount == 1, '1 out of 3 should be taxable (after a year)'
    assert taxfree_bought_cost.is_close(FVal('880.552'))
    assert taxable_bought_cost.is_close(FVal('0'))

    assert (len(accountant.events.events[asset].buys)) == 0, 'only buy should have been used'
示例#13
0
    def add_sell(self,
                 selling_asset,
                 selling_amount,
                 receiving_asset,
                 receiving_amount,
                 gain_in_profit_currency,
                 total_fee_in_profit_currency,
                 trade_rate,
                 rate_in_profit_currency,
                 timestamp,
                 loan_settlement=False,
                 is_virtual=False):

        if selling_asset not in self.events:
            self.events[selling_asset] = Events(list(), list())

        self.events[selling_asset].sells.append(
            SellEvent(
                amount=selling_amount,
                timestamp=timestamp,
                rate=rate_in_profit_currency,
                fee_rate=total_fee_in_profit_currency / selling_amount,
                gain=gain_in_profit_currency,
            ))

        debug_enabled = logger.isEnabledFor(logging.DEBUG)
        if debug_enabled:
            if loan_settlement:
                logger.debug(
                    'Loan Settlement Selling {} of "{}" for {} "{}" at {}'.
                    format(selling_amount, selling_asset,
                           gain_in_profit_currency, self.profit_currency,
                           tsToDate(timestamp, formatstr='%d/%m/%Y %H:%M:%S')))
            else:
                logger.debug(
                    'Selling {} of "{}" for {} "{}" ({} "{}" per "{}" or {} "{}" '
                    'per "{}") for a gain of {} "{}" and a fee of {} "{} at {}'
                    .format(selling_amount, selling_asset, receiving_amount,
                            receiving_asset, trade_rate, receiving_asset,
                            selling_asset, rate_in_profit_currency,
                            self.profit_currency, selling_asset,
                            gain_in_profit_currency, self.profit_currency,
                            total_fee_in_profit_currency, self.profit_currency,
                            tsToDate(timestamp,
                                     formatstr='%d/%m/%Y %H:%M:%S')))

        # now search the buys for `paid_with_asset` and  calculate profit/loss
        (taxable_amount, taxable_bought_cost,
         taxfree_bought_cost) = self.search_buys_calculate_profit(
             selling_amount, selling_asset, timestamp)
        general_profit_loss = 0
        taxable_profit_loss = 0

        # If we don't include crypto2crypto and we sell for crypto, stop here
        if receiving_asset not in FIAT_CURRENCIES and not self.include_crypto2crypto:
            return

        # calculate profit/loss
        if not loan_settlement or (loan_settlement
                                   and self.count_profit_for_settlements):
            taxable_gain = taxable_gain_for_sell(
                taxable_amount=taxable_amount,
                rate_in_profit_currency=rate_in_profit_currency,
                total_fee_in_profit_currency=total_fee_in_profit_currency,
                selling_amount=selling_amount,
            )

            general_profit_loss = gain_in_profit_currency - (
                taxfree_bought_cost + taxable_bought_cost +
                total_fee_in_profit_currency)
            taxable_profit_loss = taxable_gain - taxable_bought_cost

        # should never happen, should be stopped at the main loop
        assert timestamp <= self.query_end_ts, (
            "Trade time > query_end_ts found in adding to sell event")

        # count profit/losses if we are inside the query period
        if timestamp >= self.query_start_ts:
            if loan_settlement:
                # If it's a loan settlement we are charged both the fee and the gain
                settlement_loss = gain_in_profit_currency + total_fee_in_profit_currency
                self.settlement_losses += settlement_loss
                if debug_enabled:
                    logger.debug("Loan Settlement Loss: {} {}".format(
                        settlement_loss, self.profit_currency))
            elif debug_enabled:
                logger.debug("Taxable P/L: {} {} General P/L: {} {}".format(
                    taxable_profit_loss,
                    self.profit_currency,
                    general_profit_loss,
                    self.profit_currency,
                ))

            self.general_trade_profit_loss += general_profit_loss
            self.taxable_trade_profit_loss += taxable_profit_loss

            if loan_settlement:
                self.csv_exporter.add_loan_settlement(
                    asset=selling_asset,
                    amount=selling_amount,
                    rate_in_profit_currency=rate_in_profit_currency,
                    total_fee_in_profit_currency=total_fee_in_profit_currency,
                    timestamp=timestamp,
                )
            else:
                self.csv_exporter.add_sell(
                    selling_asset=selling_asset,
                    rate_in_profit_currency=rate_in_profit_currency,
                    total_fee_in_profit_currency=total_fee_in_profit_currency,
                    gain_in_profit_currency=gain_in_profit_currency,
                    selling_amount=selling_amount,
                    receiving_asset=receiving_asset,
                    receiving_amount=receiving_amount,
                    receiving_asset_rate_in_profit_currency=self.
                    get_rate_in_profit_currency(
                        receiving_asset,
                        timestamp,
                    ),
                    taxable_amount=taxable_amount,
                    taxable_bought_cost=taxable_bought_cost,
                    timestamp=timestamp,
                    is_virtual=is_virtual,
                )
示例#14
0
    def add_sell(
        self,
        selling_asset: Asset,
        selling_amount: FVal,
        receiving_asset: Optional[Asset],
        receiving_amount: Optional[FVal],
        gain_in_profit_currency: FVal,
        total_fee_in_profit_currency: Fee,
        trade_rate: FVal,
        rate_in_profit_currency: FVal,
        timestamp: Timestamp,
        loan_settlement: bool = False,
        is_virtual: bool = False,
    ) -> None:

        if selling_asset not in self.events:
            self.events[selling_asset] = Events(list(), list())

        self.events[selling_asset].sells.append(
            SellEvent(
                amount=selling_amount,
                timestamp=timestamp,
                rate=rate_in_profit_currency,
                fee_rate=total_fee_in_profit_currency / selling_amount,
                gain=gain_in_profit_currency,
            ), )

        self.handle_prefork_asset_sells(selling_asset, selling_amount,
                                        timestamp)

        if loan_settlement:
            log.debug(
                'Loan Settlement Selling Event',
                sensitive_log=True,
                selling_amount=selling_amount,
                selling_asset=selling_asset,
                gain_in_profit_currency=gain_in_profit_currency,
                profit_currency=self.profit_currency,
                timestamp=timestamp,
            )
        else:
            log.debug(
                'Selling Event',
                sensitive_log=True,
                selling_amount=selling_amount,
                selling_asset=selling_asset,
                receiving_amount=receiving_amount,
                receiving_asset=receiving_asset,
                rate=trade_rate,
                rate_in_profit_currency=rate_in_profit_currency,
                profit_currency=self.profit_currency,
                gain_in_profit_currency=gain_in_profit_currency,
                fee_in_profit_currency=total_fee_in_profit_currency,
                timestamp=timestamp,
            )

        # now search the buys for `paid_with_asset` and calculate profit/loss
        (
            taxable_amount,
            taxable_bought_cost,
            taxfree_bought_cost,
        ) = self.search_buys_calculate_profit(
            selling_amount,
            selling_asset,
            timestamp,
        )
        general_profit_loss = 0
        taxable_profit_loss = 0

        # If we don't include crypto2crypto and we sell for crypto, stop here
        if receiving_asset and not receiving_asset.is_fiat(
        ) and not self.include_crypto2crypto:
            return

        # calculate profit/loss
        if not loan_settlement or (loan_settlement
                                   and self.count_profit_for_settlements):
            taxable_gain = taxable_gain_for_sell(
                taxable_amount=taxable_amount,
                rate_in_profit_currency=rate_in_profit_currency,
                total_fee_in_profit_currency=total_fee_in_profit_currency,
                selling_amount=selling_amount,
            )

            general_profit_loss = gain_in_profit_currency - (
                taxfree_bought_cost + taxable_bought_cost +
                total_fee_in_profit_currency)
            taxable_profit_loss = taxable_gain - taxable_bought_cost

        # should never happen, should be stopped at the main loop
        assert timestamp <= self.query_end_ts, (
            "Trade time > query_end_ts found in adding to sell event")

        # count profit/losses if we are inside the query period
        if timestamp >= self.query_start_ts:
            if loan_settlement:
                # If it's a loan settlement we are charged both the fee and the gain
                settlement_loss = gain_in_profit_currency + total_fee_in_profit_currency
                expected = rate_in_profit_currency * selling_amount + total_fee_in_profit_currency
                msg = (
                    f'Expected settlement loss mismatch. rate_in_profit_currency'
                    f' ({rate_in_profit_currency}) * selling_amount'
                    f' ({selling_amount}) + total_fee_in_profit_currency'
                    f' ({total_fee_in_profit_currency}) != settlement_loss '
                    f'({settlement_loss})')
                assert expected == settlement_loss, msg
                self.settlement_losses += settlement_loss
                log.debug(
                    'Loan Settlement Loss',
                    sensitive_log=True,
                    settlement_loss=settlement_loss,
                    profit_currency=self.profit_currency,
                )
            else:
                log.debug(
                    "After Sell Profit/Loss",
                    sensitive_log=True,
                    taxable_profit_loss=taxable_profit_loss,
                    general_profit_loss=general_profit_loss,
                    profit_currency=self.profit_currency,
                )

            self.general_trade_profit_loss += general_profit_loss
            self.taxable_trade_profit_loss += taxable_profit_loss

            if loan_settlement:
                self.csv_exporter.add_loan_settlement(
                    asset=selling_asset,
                    amount=selling_amount,
                    rate_in_profit_currency=rate_in_profit_currency,
                    total_fee_in_profit_currency=total_fee_in_profit_currency,
                    timestamp=timestamp,
                )
            else:
                assert receiving_asset, 'Here receiving asset should have a value'
                self.csv_exporter.add_sell(
                    selling_asset=selling_asset,
                    rate_in_profit_currency=rate_in_profit_currency,
                    total_fee_in_profit_currency=total_fee_in_profit_currency,
                    gain_in_profit_currency=gain_in_profit_currency,
                    selling_amount=selling_amount,
                    receiving_asset=receiving_asset,
                    receiving_amount=receiving_amount,
                    receiving_asset_rate_in_profit_currency=self.
                    get_rate_in_profit_currency(
                        receiving_asset,
                        timestamp,
                    ),
                    taxable_amount=taxable_amount,
                    taxable_bought_cost=taxable_bought_cost,
                    timestamp=timestamp,
                    is_virtual=is_virtual,
                )
示例#15
0
    def add_buy(self,
                bought_asset,
                bought_amount,
                paid_with_asset,
                trade_rate,
                trade_fee,
                fee_currency,
                timestamp,
                is_virtual=False):
        paid_with_asset_rate = self.get_rate_in_profit_currency(
            paid_with_asset, timestamp)
        buy_rate = paid_with_asset_rate * trade_rate
        fee_price_in_profit_currency = 0
        if trade_fee != 0:
            fee_price_in_profit_currency = self.price_historian.query_historical_price(
                fee_currency, self.profit_currency, timestamp)

        self.handle_prefork_acquisitions(bought_asset=bought_asset,
                                         bought_amount=bought_amount,
                                         paid_with_asset=paid_with_asset,
                                         trade_rate=trade_rate,
                                         trade_fee=trade_fee,
                                         fee_currency=fee_currency,
                                         timestamp=timestamp)

        if bought_asset not in self.events:
            self.events[bought_asset] = Events(list(), list())

        fee_cost = fee_price_in_profit_currency * trade_fee
        gross_cost = bought_amount * buy_rate
        cost = gross_cost + fee_cost

        self.events[bought_asset].buys.append(
            BuyEvent(amount=bought_amount,
                     timestamp=timestamp,
                     rate=buy_rate,
                     fee_rate=fee_cost / bought_amount,
                     cost=cost))
        log.debug(
            'Buy Event',
            sensitive_log=True,
            bought_amount=bought_amount,
            bought_asset=bought_asset,
            paid_with_asset=paid_with_asset,
            rate=trade_rate,
            rate_in_profit_currency=buy_rate,
            profit_currency=self.profit_currency,
            timestamp=timestamp,
        )

        self.csv_exporter.add_buy(
            bought_asset=bought_asset,
            rate=buy_rate,
            fee_cost=fee_cost,
            amount=bought_amount,
            gross_cost=gross_cost,
            cost=cost,
            paid_with_asset=paid_with_asset,
            paid_with_asset_rate=paid_with_asset_rate,
            timestamp=timestamp,
            is_virtual=is_virtual,
        )
示例#16
0
    def add_buy(
        self,
        bought_asset: Asset,
        bought_amount: FVal,
        paid_with_asset: Asset,
        trade_rate: FVal,
        fee_in_profit_currency: Fee,
        fee_currency: Asset,
        timestamp: Timestamp,
        is_virtual: bool = False,
    ) -> None:
        paid_with_asset_rate = self.get_rate_in_profit_currency(
            paid_with_asset, timestamp)
        buy_rate = paid_with_asset_rate * trade_rate

        self.handle_prefork_asset_buys(
            bought_asset=bought_asset,
            bought_amount=bought_amount,
            paid_with_asset=paid_with_asset,
            trade_rate=trade_rate,
            fee_in_profit_currency=fee_in_profit_currency,
            fee_currency=fee_currency,
            timestamp=timestamp,
        )

        if bought_asset not in self.events:
            self.events[bought_asset] = Events(list(), list())

        gross_cost = bought_amount * buy_rate
        cost_in_profit_currency = gross_cost + fee_in_profit_currency

        self.events[bought_asset].buys.append(
            BuyEvent(
                amount=bought_amount,
                timestamp=timestamp,
                rate=buy_rate,
                fee_rate=fee_in_profit_currency / bought_amount,
            ), )
        log.debug(
            'Buy Event',
            sensitive_log=True,
            bought_amount=bought_amount,
            bought_asset=bought_asset,
            paid_with_asset=paid_with_asset,
            rate=trade_rate,
            rate_in_profit_currency=buy_rate,
            profit_currency=self.profit_currency,
            timestamp=timestamp,
        )

        if timestamp >= self.query_start_ts:
            self.csv_exporter.add_buy(
                bought_asset=bought_asset,
                rate=buy_rate,
                fee_cost=fee_in_profit_currency,
                amount=bought_amount,
                cost=cost_in_profit_currency,
                paid_with_asset=paid_with_asset,
                paid_with_asset_rate=paid_with_asset_rate,
                timestamp=timestamp,
                is_virtual=is_virtual,
            )
示例#17
0
    def add_sell(
        self,
        selling_asset,
        selling_amount,
        receiving_asset,
        receiving_amount,
        gain_in_profit_currency,
        total_fee_in_profit_currency,
        trade_rate,
        rate_in_profit_currency,
        timestamp,
        loan_settlement=False,
        is_virtual=False,
    ):

        if selling_asset not in self.events:
            self.events[selling_asset] = Events(list(), list())

        self.events[selling_asset].sells.append(
            SellEvent(
                amount=selling_amount,
                timestamp=timestamp,
                rate=rate_in_profit_currency,
                fee_rate=total_fee_in_profit_currency / selling_amount,
                gain=gain_in_profit_currency,
            ))

        if loan_settlement:
            log.debug(
                'Loan Settlement Selling Event',
                sensitive_log=True,
                selling_amount=selling_amount,
                selling_asset=selling_asset,
                gain_in_profit_currency=gain_in_profit_currency,
                profit_currency=self.profit_currency,
                timestamp=timestamp,
            )
        else:
            log.debug(
                'Selling Event',
                sensitive_log=True,
                selling_amount=selling_amount,
                selling_asset=selling_asset,
                receiving_amount=receiving_amount,
                receiving_asset=receiving_asset,
                rate=trade_rate,
                rate_in_profit_currency=rate_in_profit_currency,
                profit_currency=self.profit_currency,
                gain_in_profit_currency=gain_in_profit_currency,
                fee_in_profit_currency=total_fee_in_profit_currency,
                timestamp=timestamp,
            )

        # now search the buys for `paid_with_asset` and  calculate profit/loss
        (taxable_amount, taxable_bought_cost,
         taxfree_bought_cost) = self.search_buys_calculate_profit(
             selling_amount, selling_asset, timestamp)
        general_profit_loss = 0
        taxable_profit_loss = 0

        # If we don't include crypto2crypto and we sell for crypto, stop here
        if receiving_asset not in FIAT_CURRENCIES and not self.include_crypto2crypto:
            return

        # calculate profit/loss
        if not loan_settlement or (loan_settlement
                                   and self.count_profit_for_settlements):
            taxable_gain = taxable_gain_for_sell(
                taxable_amount=taxable_amount,
                rate_in_profit_currency=rate_in_profit_currency,
                total_fee_in_profit_currency=total_fee_in_profit_currency,
                selling_amount=selling_amount,
            )

            general_profit_loss = gain_in_profit_currency - (
                taxfree_bought_cost + taxable_bought_cost +
                total_fee_in_profit_currency)
            taxable_profit_loss = taxable_gain - taxable_bought_cost

        # should never happen, should be stopped at the main loop
        assert timestamp <= self.query_end_ts, (
            "Trade time > query_end_ts found in adding to sell event")

        # count profit/losses if we are inside the query period
        if timestamp >= self.query_start_ts:
            if loan_settlement:
                # If it's a loan settlement we are charged both the fee and the gain
                settlement_loss = gain_in_profit_currency + total_fee_in_profit_currency
                self.settlement_losses += settlement_loss
                log.debug(
                    'Loan Settlement Loss',
                    sensitive_log=True,
                    settlement_loss=settlement_loss,
                    profit_currency=self.profit_currency,
                )
            else:
                log.debug(
                    "After Sell Profit/Loss",
                    sensitive_log=True,
                    taxable_profit_loss=taxable_profit_loss,
                    general_profit_loss=general_profit_loss,
                    profit_currency=self.profit_currency,
                )

            self.general_trade_profit_loss += general_profit_loss
            self.taxable_trade_profit_loss += taxable_profit_loss

            if loan_settlement:
                self.csv_exporter.add_loan_settlement(
                    asset=selling_asset,
                    amount=selling_amount,
                    rate_in_profit_currency=rate_in_profit_currency,
                    total_fee_in_profit_currency=total_fee_in_profit_currency,
                    timestamp=timestamp,
                )
            else:
                self.csv_exporter.add_sell(
                    selling_asset=selling_asset,
                    rate_in_profit_currency=rate_in_profit_currency,
                    total_fee_in_profit_currency=total_fee_in_profit_currency,
                    gain_in_profit_currency=gain_in_profit_currency,
                    selling_amount=selling_amount,
                    receiving_asset=receiving_asset,
                    receiving_amount=receiving_amount,
                    receiving_asset_rate_in_profit_currency=self.
                    get_rate_in_profit_currency(
                        receiving_asset,
                        timestamp,
                    ),
                    taxable_amount=taxable_amount,
                    taxable_bought_cost=taxable_bought_cost,
                    timestamp=timestamp,
                    is_virtual=is_virtual,
                )