Skip to content

Commit

Permalink
Expected tax calculation improved
Browse files Browse the repository at this point in the history
  • Loading branch information
softandiron committed Aug 3, 2021
1 parent f006ca6 commit c4432d3
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 12 deletions.
15 changes: 12 additions & 3 deletions excel_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def get_color(num):

def build_excel_file(my_positions, my_operations, rates_today_cb, market_rate_today,
average_percent, portfolio_cost_rub_market, sum_profile,
investing_period_str, cash_rub, payin_payout, xirr_value, logger=logging.getLogger()):
investing_period_str, cash_rub, payin_payout, xirr_value, tax_rate, logger=logging.getLogger()):

logger.info('creating excel file..')
excel_file_name = 'tinkoffReport_' + data_parser.account_data['now_date'].strftime('%Y.%b.%d') + '.xlsx'
Expand Down Expand Up @@ -140,7 +140,7 @@ def print_totals(row, col):
worksheet_port.write(row, col, 'Рубль деревянный кэшем', cell_format['left'])
for shift in [2, 10, 12]:
worksheet_port.write(row, col + shift, cash_rub, cell_format['RUB'])
for shift in set(range(1, 16)) - {2, 10, 11, 12}:
for shift in set(range(1, 17)) - {2, 10, 11, 12}:
worksheet_port.write(row, col + shift, '-', cell_format['center'])
row += 1

Expand All @@ -155,8 +155,17 @@ def print_totals(row, col):
worksheet_port.write(row + 1, col + 8, average_percent, cell_format['perc'])

worksheet_port.write(row + 1, col + 12, sum_profile['portfolio_value_rub_cb'], cell_format['RUB'])

worksheet_port.write(row + 1, col + 14, sum_profile['pos_ave_buy_rub'], cell_format['RUB'])
worksheet_port.write(row + 1, col + 16, sum_profile['exp_tax'], cell_format['RUB'])
worksheet_port.write(row + 2, col + 14, 'profit:', cell_format['bold_right'])
worksheet_port.write(row + 3, col + 14, 'loss:', cell_format['bold_right'])

worksheet_port.write(row + 2, col + 15, sum_profile['profit'], cell_format['RUB'])
worksheet_port.write(row + 3, col + 15, sum_profile['loss'], cell_format['RUB'])

worksheet_port.write(row + 2, col + 16, sum_profile['profit_tax'], cell_format['RUB'])
worksheet_port.write(row + 3, col + 16, sum_profile['loss_tax'], cell_format['RUB'])
worksheet_port.write(row + 4, col + 16, sum_profile['exp_tax'], cell_format['RUB'])

return row + 1

Expand Down
40 changes: 31 additions & 9 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def creating_positions_objects():
ave_buy_price_rub = calculate_ave_buy_price_rub(this_pos)
sum_buy_rub = ave_buy_price_rub * this_pos.balance

tax_base = Decimal(max(0, market_cost_rub_cb - sum_buy_rub))
tax_base = market_cost_rub_cb - sum_buy_rub
exp_tax = tax_base * Decimal(tax_rate / 100)

logger.info(this_pos.name)
Expand Down Expand Up @@ -205,8 +205,32 @@ def calculate_sum_pos_ave_buy_rub():
return sum(pos.sum_buy_rub for pos in my_positions)


def calculate_profit_sum():
list = []
for pos in my_positions:
if pos.tax_base > 0:
list.append(pos.tax_base)
return sum(list)


def calculate_profit_tax():
return round(sum_profile['profit'] * Decimal(tax_rate / 100), 2)


def calculate_loss_tax():
return round(sum_profile['loss'] * Decimal(tax_rate / 100), 2)


def calculate_loss_sum():
list = []
for pos in my_positions:
if pos.tax_base < 0:
list.append(pos.tax_base)
return sum(list)


def calculate_sum_exp_tax():
return sum(pos.exp_tax for pos in my_positions)
return Decimal(max(0, sum(pos.exp_tax for pos in my_positions)))


def create_operations_objects():
Expand Down Expand Up @@ -250,34 +274,28 @@ def calculate_operations_sums_rub(current_op_type):
def xnpv(valuesPerDate, rate):
# Calculate the irregular net present value.
days_per_year = 365.0

if rate == -1.0:
return float('inf')

t0 = min(valuesPerDate.keys())

if rate <= -1.0:
return sum([-abs(vi) / (-1.0 - rate)**((ti - t0).days / days_per_year) for ti, vi in valuesPerDate.items()])

return sum([vi / (1.0 + rate)**((ti - t0).days / days_per_year) for ti, vi in valuesPerDate.items()])


def xirr(valuesPerDate):
# Calculate the irregular internal rate of return
if not valuesPerDate:
return None

if all(v >= 0 for v in valuesPerDate.values()):
return float("inf")
if all(v <= 0 for v in valuesPerDate.values()):
return -float("inf")

result = None
try:
result = scipy.optimize.newton(lambda r: xnpv(valuesPerDate, r), 0)
except (RuntimeError, OverflowError): # Failed to converge?
result = scipy.optimize.brentq(lambda r: xnpv(valuesPerDate, r), -0.999999999999999, 1e20, maxiter=10**6)

if not isinstance(result, complex):
return result
else:
Expand Down Expand Up @@ -343,6 +361,10 @@ def calculate_xirr(operations, portfolio_value):
sum_profile['portfolio_value_rub_cb'] = calculate_cb_value_rub_sum()
sum_profile['pos_ave_buy_rub'] = calculate_sum_pos_ave_buy_rub()
sum_profile['exp_tax'] = calculate_sum_exp_tax()
sum_profile['profit'] = calculate_profit_sum()
sum_profile['loss'] = calculate_loss_sum()
sum_profile['profit_tax'] = calculate_profit_tax()
sum_profile['loss_tax'] = calculate_loss_tax()

my_operations = create_operations_objects()

Expand All @@ -361,6 +383,6 @@ def calculate_xirr(operations, portfolio_value):
# EXCEL
build_excel_file(my_positions, my_operations, rates_today_cb, market_rate_today,
average_percent, portfolio_cost_rub_market, sum_profile,
investing_period_str, cash_rub, payin_payout, xirr_value, logger)
investing_period_str, cash_rub, payin_payout, xirr_value, tax_rate, logger)

logger.info(f'done in {time.time() - start_time:.2f} seconds')

0 comments on commit c4432d3

Please sign in to comment.