def prepare_interests_report(interests: List[Interest], cbr_client_usd: cbr.ExchangeRatesRUB) -> pandas.DataFrame: operation_date_column = 'date' df_data = [ (i + 1, pandas.to_datetime(x.date), x.amount, x.description, x.date.year) for i, x in enumerate(interests) ] df = pandas.DataFrame(df_data, columns=['N', operation_date_column, 'amount', 'description', 'tax_year']) df['rate'] = df.apply(lambda x: cbr_client_usd.get_rate(x['amount'].currency, x[operation_date_column]), axis=1) df['amount_rub'] = df.apply(lambda x: cbr_client_usd.convert_to_rub(x['amount'], x[operation_date_column]), axis=1) return df
def test_exchange_rates_rub(trade_date: datetime, currency: Currency, expect_rate: Money): try: p = ExchangeRatesRUB(year_from=2015, cache_dir=None) except ConnectionError as ex: pytest.skip(f'connection error: {ex}') return rate = p.get_rate(currency, trade_date) assert rate == expect_rate, f'{trade_date}: {rate} != {expect_rate}'
def prepare_trades_report(finished_trades: List[FinishedTrade], cbr_client_usd: cbr.ExchangeRatesRUB) -> pandas.DataFrame: """ Расчёт расхода/дохода и финансового результата по закрытым сделкам. Общая методика расчёта расхода/дохода по сделке: [сумма сделки] * [курс валюты на дату поставки] +/- [сумма комиссии] * [курс валюты на дату сделки] """ trade_date_column = 'trade_date' tax_date_column = 'settle_date' df = pandas.DataFrame(finished_trades, columns=finished_trades[0].fields) df[trade_date_column] = df[trade_date_column].dt.normalize() df[tax_date_column] = pandas.to_datetime(df[tax_date_column]) tax_years = df.groupby('N')[tax_date_column].max().map(lambda x: x.year).rename('tax_year') df = df.join(tax_years, how='left', on='N') df['price_rub'] = df.apply(lambda x: cbr_client_usd.convert_to_rub(x['price'], x[tax_date_column]), axis=1) df['fee_per_piece_rub'] = df.apply(lambda x: cbr_client_usd.convert_to_rub(x['fee_per_piece'], x[trade_date_column]), axis=1) df['fee'] = df.apply(lambda x: (x['fee_per_piece'] * abs(x['quantity'])), axis=1) df['total'] = df.apply( lambda x: compute_total_cost(x['quantity'], x['price'], x['fee_per_piece']), axis=1, ) df['total_rub'] = df.apply( lambda x: compute_total_cost(x['quantity'], x['price_rub'], x['fee_per_piece_rub']), axis=1, ) df['settle_rate'] = df.apply(lambda x: cbr_client_usd.get_rate(x['price'].currency, x[tax_date_column]), axis=1) df['fee_rate'] = df.apply(lambda x: cbr_client_usd.get_rate(x['fee_per_piece'].currency, x[trade_date_column]), axis=1) df['profit_rub'] = df['total_rub'] profit = df.groupby('N')['profit_rub'].sum().reset_index().set_index('N') df = df.join(profit, how='left', on='N', lsuffix='_delete') df.drop(columns=['profit_rub_delete'], axis=0, inplace=True) df.loc[~df.index.isin(df.groupby('N')[trade_date_column].idxmax()), 'profit_rub'] = Money(0, Currency.RUB) return df
def prepare_dividends_report(dividends: List[Dividend], cbr_client_usd: cbr.ExchangeRatesRUB, verbose: bool) -> pandas.DataFrame: operation_date_column = 'date' if not verbose: dividends = [x for x in dividends if x.amount.amount != 0 or x.tax.amount != 0] # remove reversed dividends df_data = [(i + 1, x.ticker, pandas.to_datetime(x.date), x.amount, x.tax) for i, x in enumerate(dividends)] df = pandas.DataFrame(df_data, columns=['N', 'ticker', 'date', 'amount', 'tax_paid']) df['tax_year'] = df[operation_date_column].map(lambda x: x.year) df['rate'] = df.apply(lambda x: cbr_client_usd.get_rate(x['amount'].currency, x[operation_date_column]), axis=1) df['amount_rub'] = df.apply(lambda x: cbr_client_usd.convert_to_rub(x['amount'], x[operation_date_column]), axis=1) df['tax_paid_rub'] = df.apply(lambda x: cbr_client_usd.convert_to_rub(x['tax_paid'], x[operation_date_column]), axis=1) df['tax_rate'] = df.apply(lambda x: round(x['tax_paid'].amount * 100 / x['amount'].amount, 2), axis=1) return df
def prepare_fees_report(fees: List[Fee], cbr_client_usd: cbr.ExchangeRatesRUB, verbose: bool) -> pandas.DataFrame: operation_date_column = 'date' df_data = [ (i + 1, pandas.to_datetime(x.date), x.amount, x.description, x.date.year) for i, x in enumerate(fees) ] df = pandas.DataFrame(df_data, columns=['N', operation_date_column, 'amount', 'description', 'tax_year']) df['rate'] = df.apply(lambda x: cbr_client_usd.get_rate(x['amount'].currency, x[operation_date_column]), axis=1) df['amount_rub'] = df.apply(lambda x: cbr_client_usd.convert_to_rub(x['amount'], x[operation_date_column]), axis=1) if not verbose: df['abs_amount_del'] = df.apply(lambda x: abs(x.amount.amount), axis=1) df.drop_duplicates(subset=[operation_date_column, 'description', 'abs_amount_del'], keep=False, inplace=True) df.drop(columns=['abs_amount_del'], inplace=True) df['N'] = range(1, len(df) + 1) return df
def test_exchange_rates_rub(): test_cases = [ (datetime(2015, 1, 15), Money('66.0983', Currency.RUB)), (datetime(2015, 3, 7), Money('59.9938', Currency.RUB)), (datetime(2015, 3, 8), Money('59.9938', Currency.RUB)), (datetime(2020, 3, 31), Money('77.7325', Currency.RUB)), ] try: p = ExchangeRatesRUB(year_from=2015, cache_dir=None) except ConnectionError as ex: pytest.skip(f'connection error: {ex}') return for tc in test_cases: rate = p.get_rate(tc[0]) assert rate == tc[1], f'{tc[0]}: {rate} != {tc[1]}'
def test_convert_to_rub(): client_usd = ExchangeRatesRUB() rate_date = datetime(2020, 3, 31) expected_rate = client_usd.get_rate(Currency.USD, rate_date) assert expected_rate.amount == Decimal('77.7325') test_usd = Money(10.98, Currency.USD) res = client_usd.convert_to_rub(test_usd, rate_date) assert res.amount == Decimal('853.50285') assert res.currency == Currency.RUB test_rub = Money(Decimal('858.3066'), Currency.RUB) res = client_usd.convert_to_rub(test_rub, rate_date) assert res.amount == Decimal('858.3066') assert res.currency == Currency.RUB