Skip to content

Commit

Permalink
The old corporate actions tax report code was removed as it is not us…
Browse files Browse the repository at this point in the history
…ed after change of transfer and corporate actions processing.
  • Loading branch information
titov-vv committed May 23, 2024
1 parent 38f4146 commit 58de81a
Showing 1 changed file with 0 additions and 208 deletions.
208 changes: 0 additions & 208 deletions jal/data_export/tax_reports/russia.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,211 +384,3 @@ def prepare_broker_interest(self):
interests_report.append(line)
self.insert_totals(interests_report, ["amount", "amount_rub", "tax_rub"])
return interests_report

# -----------------------------------------------------------------------------------------------------------------------
def prepare_corporate_actions(self):
corporate_actions_report = []
trades = self.account.closed_trades_list()
trades = [x for x in trades if x.close_operation().type() == LedgerTransaction.Trade]
trades = [x for x in trades if x.open_operation().type() == LedgerTransaction.CorporateAction]
trades = [x for x in trades if self.year_begin <= x.close_operation().settlement() <= self.year_end]
trades = sorted(trades, key=lambda x: (x.asset().symbol(self.account_currency.id()), x.close_operation().timestamp()))
group = 1
share = Decimal('1.0') # This will track share of processed asset, so it starts from 100.0%
previous_symbol = ""
for trade in trades:
lines = []
sale = trade.close_operation()
t_rate = self.account_currency.quote(sale.timestamp(), self._currency_id)[1]
if self.use_settlement:
s_rate = self.account_currency.quote(sale.settlement(), self._currency_id)[1]
else:
s_rate = t_rate
if previous_symbol != sale.asset().symbol(self.account_currency.id()):
# Clean processed qty records if symbol have changed
self._processed_trade_qty = {}
if sale.settlement() >= self.year_begin: # Don't put sub-header of operation is out of scope
corporate_actions_report.append({
'report_template': "symbol_header",
'report_group': 0,
'description': f"Сделки по бумаге: {sale.asset().symbol(self.account_currency.id())} - {sale.asset().name()}"
})
previous_symbol = sale.asset().symbol(self.account_currency.id())
amount = round(sale.price() * trade.qty(), 2)
amount_rub = round(amount * s_rate, 2)
fee_rub = round(sale.fee() * t_rate, 2)
if sale.timestamp() < self.year_begin: # Don't show deal that is before report year (level = -1)
self.proceed_corporate_action(lines, trade, trade.qty(), share, -1, group)
else:
lines.append({
'report_template': "trade",
'report_group': group,
'operation': "Продажа",
't_date': sale.timestamp(),
't_rate': t_rate,
's_date': sale.settlement(),
's_rate': s_rate,
'symbol': sale.asset().symbol(self.account_currency.id()),
'isin': sale.asset().isin(),
'trade_number': sale.number(),
'price': sale.price(),
'qty': trade.qty(),
'amount': amount,
'amount_rub': amount_rub,
'fee': sale.fee(),
'fee_rub': fee_rub,
'basis_ratio': Decimal('100') * share,
'income_rub': amount_rub,
'spending_rub': fee_rub
})
if sale.asset().type() == PredefinedAsset.Bond:
self.output_accrued_interest(lines, sale, 1, 0)
self.proceed_corporate_action(lines, trade, trade.qty(), share, 1, group)
self.insert_totals(lines, ["income_rub", "spending_rub"])
corporate_actions_report += lines
group += 1
return corporate_actions_report

# actions - mutable list of tax records to output into json-report
# trade - JalClosedTrade object, for which we need to proceed with opening corporate action
# qty - amount of asset to process
# share - value share that is being processed currently
# level - how deep we are in a chain of events (is used for correct indents)
# group - use for odd/even lines grouping in the report
def proceed_corporate_action(self, actions, trade, qty, share, level, group):
asset_id, qty, share = self.output_corp_action(actions, trade.open_operation(), trade.asset(), qty, share, level, group)
next_level = -1 if level == -1 else (level + 1)
self.next_corporate_action(actions, trade, qty, share, next_level, group)

def next_corporate_action(self, actions, trade, qty, share, level, group):
# get list of deals that were closed as result of current corporate action
trades = self.account.closed_trades_list()
trades = [x for x in trades if x.close_operation().type() == LedgerTransaction.CorporateAction]
trades = [x for x in trades if x.close_operation().id() == trade.open_operation().id()]
for item in trades:
if item.open_operation().type() == LedgerTransaction.Trade:
qty = self.output_purchase(actions, item.open_operation(), qty, share, level, group)
elif item.open_operation().type() == LedgerTransaction.CorporateAction:
self.proceed_corporate_action(actions, item, qty, share, level, group)
else:
assert False, "Unexpected opening transaction"

def output_purchase(self, actions, purchase, proceed_qty, share, level, group):
if proceed_qty <= Decimal('0'):
return proceed_qty
t_rate = self.account_currency.quote(purchase.timestamp(), self._currency_id)[1]
if self.use_settlement:
s_rate = self.account_currency.quote(purchase.settlement(), self._currency_id)[1]
else:
s_rate = t_rate
if purchase.id() in self._processed_trade_qty: # we have some qty processed already
qty = purchase.qty() - self._processed_trade_qty[purchase.id()]
else:
qty = purchase.qty()
if qty <= Decimal('0'):
return proceed_qty # This trade was fully matched during previous operations processing
deal_qty = qty
qty = proceed_qty if proceed_qty < deal_qty else deal_qty
amount = round(purchase.price() * qty, 2)
amount_rub = round(amount * s_rate, 2)
fee = purchase.fee() * qty / deal_qty
fee_rub = round(fee * t_rate, 2)
# Update processed quantity for current _purchase_ operation
self._processed_trade_qty[purchase.id()] = self._processed_trade_qty.get(purchase.id(), 0) + qty
if level >= 0: # Don't output if level==-1, i.e. corp action is out of report scope
actions.append({
'report_template': "trade",
'report_group': group,
'operation': ' ' * level * 3 + "Покупка",
'trade_number': purchase.number(),
'symbol': purchase.asset().symbol(self.account_currency.id()),
'isin': purchase.asset().isin(),
't_date': purchase.timestamp(),
't_rate': t_rate,
's_date': purchase.settlement(),
's_rate': s_rate,
'basis_ratio': Decimal('100') * share,
'qty': qty,
'price': purchase.price(),
'amount': amount,
'amount_rub': amount_rub,
'fee': fee,
'fee_rub': fee_rub,
'income_rub': Decimal('0'),
'spending_rub': round(share *(amount_rub + fee_rub), 2)
})
if purchase.asset().type() == PredefinedAsset.Bond:
share = qty / deal_qty if qty < deal_qty else 1
self.output_accrued_interest(actions, purchase, share, level)
return proceed_qty - qty

# asset - is a resulting asset that is being processed at current stage
def output_corp_action(self, actions, action, asset, proceed_qty, share, level, group):
currency = JalAsset(self.account.currency())
if proceed_qty <= 0:
return proceed_qty, share
r_qty, r_share = action.get_result_for_asset(asset)
share = share * r_share
qty_before = action.qty() * proceed_qty / r_qty
if action.subtype() == CorporateAction.SpinOff:
action_results = action.get_results()
spinoff = [x for x in action_results if x['asset_id'] != action.asset().id()]
assert len(spinoff) == 1, "Multiple assets for spin-off"
spinoff = spinoff[0]
new_asset = JalAsset(spinoff['asset_id'])
old_asset_name = f"{action.asset().symbol(currency.id())} ({action.asset().isin()})"
new_asset_name = f"{new_asset.symbol(currency.id())} ({new_asset.isin()})"
display_share = Decimal('100') * Decimal(spinoff['value_share'])
else:
old_asset_name = f"{action.asset().symbol(currency.id())} ({action.asset().isin()})"
new_asset_name = f"{asset.symbol(currency.id())} ({asset.isin()})"
display_share = Decimal('100') * r_share
note = self.CorpActionText[action.subtype()].format(old=old_asset_name, new=new_asset_name,
before=remove_exponent(qty_before),
after=remove_exponent(proceed_qty), share=display_share)
if level >= 0: # Don't output if level==-1, i.e. corp action is out of report scope
actions.append({
'report_template': "action",
'report_group': group,
'operation': ' ' * level * 3 + "Корп. действие",
'action_date': action.timestamp(),
'action_number': action.number(),
'symbol': action.asset().symbol(currency.id()),
'isin': action.asset().isin(),
'qty': action.qty(),
'description': note
})
return action.asset().id(), qty_before, share

def output_accrued_interest(self, actions, operation, share, level):
country = self.account.country()
accrued_interest = operation.accrued_interest()
if accrued_interest == Decimal('0'):
return
rate = self.account_currency.quote(operation.timestamp(), self._currency_id)[1]
interest = accrued_interest if share == 1 else share * accrued_interest
interest_rub = abs(round(interest * rate, 2))
if interest < 0: # Accrued interest paid for purchase
interest = -interest
op_name = ' ' * level * 3 + "НКД уплачен"
spending_rub = interest_rub
income_rub = Decimal('0')
else: # Accrued interest received for sale
op_name = ' ' * level * 3 + "НКД получен"
income_rub = interest_rub
spending_rub = Decimal('0')
actions.append({
'report_template': 'bond_interest',
'empty': '',
'operation': op_name,
'symbol': operation.asset().symbol(self.account_currency.id()),
'isin': operation.asset().isin(),
'number': operation.number(),
'o_date': operation.timestamp(),
'rate': rate,
'interest': interest,
'interest_rub': interest_rub,
'income_rub': income_rub,
'spending_rub': spending_rub,
'country_iso': country.iso_code()
})

0 comments on commit 58de81a

Please sign in to comment.