комментарии Sergey Solod на форуме

  1. Логотип Доллар рубль
    Будет ли введение запрета (гипотетического) на конвертацию рубля форс-мажором?

    Сугубо гипотетическая ситуация: введен пакет санкций, в котором — запрет на конвертацию рубля в доллар\евро. Может ли российский заемщик, разместивший свои валютные бонды через зависимую иностранную компанию, например, страстно многими из них любимую Ирландию, заявить, что это — форс-мажор и свои долги он кредиторам прощает? И затем в качестве жеста доброй воли предложить выкупить по 10% от номинала.
    Повторюсь, сценарий — сугубо гипотетический. У меня, конечно, ест и хрустальный шар для предсказания будущего, и прямая связь с Дедом Морозом, но ни тот, ни другой не хотят размениваться на низменные вещи вроде облигаций и валютной конвертации. 



    Авто-репост. Читать в блоге >>>
  2. Логотип S&P500 фьючерс | SPX
    ММВБ и биржа Санкт-Петербурга, почему не торгуются SPY, IVV, VOO, QQQ?
    Средние объемы торгов (источник https://www.etf.com):
    SPY — $29.94B,
    IVV - $1.79B,
    VOO — $1.82B,
    QQQ - $13.44B
    Но ни одного из этих инструментов не смог найти на российских биржах.
    Я плохо искал? Или по какой-то причине их действительно нет?

    Авто-репост. Читать в блоге >>>
  3. Логотип Finex ETF
    FXRU как прокси USD: риски, выгоды, недостатки

    Низкие или даже отрицательные доходности депозитов в ненадежных (безнадёжных) валютах вроде EURO и USD в сочетании с высокой инфляцией превратили длинные позиции в кэше USD/EURO в убыточные.

    Если же сформировать длинную валютную позицию через облигации, то возникает 15% НДФЛ и на купон, и на положительный результат при продаже (а из-за курсовой разницы в перспективе нескольких лет он скорее всего таким и будет).

        Может ли помочь ETF — обертка вокруг валютных облигаций более-менее надежных российских эмитентов — как-то улучшить совсем уж грустные итоговые доходности позиций с умеренным риском и в валюте с горизонтом >= трех лет? Например, FXRU от FinEX (комиссия 0.5%) торгуемый и в рублях на ММВБ, и в USD в Лондоне.

    На первый взгляд кажется, что сможет:

    • Расходы на комиссию — примерно равны НДФЛ по купонам (если купон 3.5%).
    • Через три года  уже применима льгота по сроку владения.
    • Двадцать три бумаги в портфеле уменьшают риск дефолта портфеля в целом. Собрать и поддерживать такой портфель самому тяжело (мягко говоря).

    Рисков и недостатков я не вижу. Что вовсе не значит, что их (рисков и недостатков) нет.

    Что думаете? Было бы особенно интересно услышать мнение @gofan777 и @Arcon (внимательно читал посты обоих, но возможно появились новые мысли).



    Авто-репост. Читать в блоге >>>
  4. Логотип Налогообложение на рынке ценных бумаг
    Инвестиционные льготы (от 3 лет владения) для счастливых владельцев AAPL
    Тема явно не для пятницы, но все же рискну.
    Продолжаю чтение Налогово Кодекса. Напомню, что согласно пп.1 п.1 ст.219.1 НК:
    «налогоплательщик имеет право на получение следующих инвестиционных налоговых вычетов, предоставляемых с учетом особенностей и в порядке, которые предусмотрены настоящей статьей: 1) в размере положительного финансового результата, полученного налогоплательщиком в налоговом периоде от реализации (погашения) ценных бумаг, обращающихся на организованном рынке ценных бумаг, указанных в подпунктах 1 и 2 пункта 3 статьи 214.1 настоящего Кодекса и находившихся в собственности налогоплательщика более трех лет;»
    А именно:
    «3. К ценным бумагам, обращающимся на организованном рынке ценных бумаг, в целях настоящей главы относятся:1) ценные бумаги, допущенные к торгам российского организатора торговли на рынке ценных бумаг, в том числе на фондовой бирже;2) инвестиционные паи открытых паевых инвестиционных фондов, управление которыми осуществляют российские управляющие компании;»

    Авто-репост. Читать в блоге >>>
  5. Охватить весь мир (MSCI ACWI) своими неумелыми руками

         Решил (не спрашивайте «зачем и почему»), что часть портфеля должна следовать за MSCI ACWI Index (ACWI, глобальный рынок акций — и развитые, и развивающиеся экономики). Самый простой путь — купить соответствующий ETF: Lyxor MSCI All Country World UCITS ETF, iShares MSCI ACWI UCITS ETF, iShares MSCI ACWI ETF, SPDR MSCI ACWI IMI UCITS ETF. Вот только минимальный TER в 0.2%  показался мне грабительским, ибо в индексе США занимают 59%, а VOO (ETF на S&P 500 от Vanguard) — 0.03% TER.

    Попробовал посчитать, во что обойдется имитация MSCI ACWI, собранная из нескольких ETF:

    Рынок

    Уд. вес, %

    ETF

    TER

    US

    59

     Vanguard S&P 500

    0.03

    Developed ex US and Canada

    24.1

    iShares Core MSCI EAFE ETF

    0.07

    Emerging Markets

    14

    iShares Core MSCI Emerging Markets ETF

    0.18

    Canada

    2.9

     Franklin FTSE Canada ETF

    0.09



    Авто-репост. Читать в блоге >>>
  6. Логотип Налогообложение на рынке ценных бумаг
    InterActiveBrokers, короткие продажи: готовим данные для налоговой декларации 3НДФЛ
    Неторопливо и коряво пишу код на Python для обработки брокерского отчета InterActiveBrokers. По завершению (надеюсь) загруженный годовой отчет в секунды превратится в xml-файл, пригодный для загрузки в личный налоговый кабинет и/или в программу «Декларация» для вывода на печать.
    Готов блок для обработки раздела «Дивиденды».
    Почти готов блок для обработки раздела «Торговля», но у меня в отчете нет коротких операций, поэтому не могу написать процедуру, «переваривающую» короткие продажи и закрытие позиций.
    Вопрос-просьба к сообществу: поделитесь отчетом, где есть и шорт, и закрытие длинных позиций. Личные данные, конечно, можно затереть.
    И если есть желающие присоединиться к разработке, милости прошу. Время декларационно кампании кажется очень далеким, но это — обманчиво. Вручную корректно обработать сотни или тысячи операций из отчета — невозможно. 

    Авто-репост. Читать в блоге >>>
  7. Логотип Interactive Brokers
    InterActiveBrokers, короткие продажи: готовим данные для налоговой декларации 3НДФЛ
    Неторопливо и коряво пишу код на Python для обработки брокерского отчета InterActiveBrokers. По завершению (надеюсь) загруженный годовой отчет в секунды превратится в xml-файл, пригодный для загрузки в личный налоговый кабинет и/или в программу «Декларация» для вывода на печать.
    Готов блок для обработки раздела «Дивиденды».
    Почти готов блок для обработки раздела «Торговля», но у меня в отчете нет коротких операций, поэтому не могу написать процедуру, «переваривающую» короткие продажи и закрытие позиций.
    Вопрос-просьба к сообществу: поделитесь отчетом, где есть и шорт, и закрытие длинных позиций. Личные данные, конечно, можно затереть.
    И если есть желающие присоединиться к разработке, милости прошу. Время декларационно кампании кажется очень далеким, но это — обманчиво. Вручную корректно обработать сотни или тысячи операций из отчета — невозможно. 

    Авто-репост. Читать в блоге >>>
  8. Логотип X5 Retail Group
    Yandex, X5 и прочие "иностранцы" не поладают под инвестиционные льготы (от 3 лет владения)?
    Почитал недавно пару статей Налогово Кодекса. Вряд ли столь же увлекательно, как хороший детектив. Но без вариантов, приходится.
    Согласно пп.1 п.1 ст.219.1 НК:
    «налогоплательщик имеет право на получение следующих инвестиционных налоговых вычетов, предоставляемых с учетом особенностей и в порядке, которые предусмотрены настоящей статьей: 1) в размере положительного финансового результата, полученного налогоплательщиком в налоговом периоде от реализации (погашения) ценных бумаг, обращающихся на организованном рынке ценных бумаг, указанных в подпунктах 1 и 2 пункта 3 статьи 214.1 настоящего Кодекса и находившихся в собственности налогоплательщика более трех лет;»

    А именно:
    «3. К ценным бумагам, обращающимся на организованном рынке ценных бумаг, в целях настоящей главы относятся:1) ценные бумаги, допущенные к торгам российского организатора торговли на рынке ценных бумаг, в том числе на фондовой бирже;2) инвестиционные паи открытых паевых инвестиционных фондов, управление которыми осуществляют российские управляющие компании;»

    В переводе с канцелярского на русский: Yandex & X5 попадают под эту льготу?

    Авто-репост. Читать в блоге >>>
  9. Логотип Налогообложение на рынке ценных бумаг
    Yandex, X5 и прочие "иностранцы" не поладают под инвестиционные льготы (от 3 лет владения)?
    Почитал недавно пару статей Налогово Кодекса. Вряд ли столь же увлекательно, как хороший детектив. Но без вариантов, приходится.
    Согласно пп.1 п.1 ст.219.1 НК:
    «налогоплательщик имеет право на получение следующих инвестиционных налоговых вычетов, предоставляемых с учетом особенностей и в порядке, которые предусмотрены настоящей статьей: 1) в размере положительного финансового результата, полученного налогоплательщиком в налоговом периоде от реализации (погашения) ценных бумаг, обращающихся на организованном рынке ценных бумаг, указанных в подпунктах 1 и 2 пункта 3 статьи 214.1 настоящего Кодекса и находившихся в собственности налогоплательщика более трех лет;»

    А именно:
    «3. К ценным бумагам, обращающимся на организованном рынке ценных бумаг, в целях настоящей главы относятся:1) ценные бумаги, допущенные к торгам российского организатора торговли на рынке ценных бумаг, в том числе на фондовой бирже;2) инвестиционные паи открытых паевых инвестиционных фондов, управление которыми осуществляют российские управляющие компании;»

    В переводе с канцелярского на русский: Yandex & X5 попадают под эту льготу?

    Авто-репост. Читать в блоге >>>
  10. Почему шорт? Let's srach begin

     Очень часто задаю себе вопрос: почему люди шортятся? Речь не о тех людях, кто выстраивает сложные схемы, оставаясь, например, нейтральными по активу, или же ждет поступления актива через н-времени, а текущая цена — вполне ОК. Нет, говорю не о них.

    Интересно, что побуждает встать в шорт сейчас в надежде откупиться дешевле в светлом будущем, которое часто вообще не наступает или наступает так поздно, что расходы по поддержанию короткой позиции и съедают весь ожидаемый доход, и закусывают параллельно психическим здоровьем шортиста.

    Вся история наблюдений за рынком говорит о том, что шорт скорее закончится убытками, чем прибылями, так как в большинстве своем цена акций растет со временем.  Школьная математика, хотя даже и не математика, а арифметика, предлагает простенькое обоснование бесперспективности шорта. Ибо:

    1. Потенциал дохода от шорта ограничен: цена актива, как правило, не бывает ниже нуля. Соответственно,  доход не может быть выше 100% от цены продажи. В случае с длинной позицией потенциал прибыли не ограничен ничем, т. к. цена может вырасти и в разы, и — если очень повезет — то и на порядки.
    2. Время всегда играет против шортиста: за поддержание короткой позиции нужно платить проценты. Поддержание длинной позиции, купленной за свои деньги, в большинстве случаев практически бесплатно, а часто и приносит деньги (дивидендные бумаги или, так тоже бывает, выплаты от тех же шортистов).
    3. И да, ставшее любимым для многих пользователей Robinhood занятие «накажи шортиста» тоже добавляет проблем  при удержании короткой позиции.

    Но люди продолжают вставать в шорт. У них есть какое-то секретное, не доступное мне знание? Или причина в том, организм просит адреналина?



    Авто-репост. Читать в блоге >>>
  11. KSTR - первый ETF в Европе с портфелем из крупнейший китайских компаний новой экономики

    Цитирую:
    «Krane Funds Advisors, американский ETF-провайдер с китайскими собственниками и со специализацией на Китае, запустил первый в Европе ETF, который предлагает доступ к 50 крупнейшим компаниям на китайском рынке STAR. KraneShares ICBCCS SSE Star Market 50 Index UCITS ETF (тикер KSTR, ISIN IE00BKPJY434) будет торговаться на Лондонской фондовой бирже. Коэффициент общих затрат (TER) 0,82%.
    KSTR отслеживает индекс Science and Technology Innovation Board 50 Шанхайской фондовой биржи (SSE), который включает 50 крупнейших компаний, котируемых на Science and Technology Innovation Board (STAR).Рынок STAR был запущен Шанхайской фондовой биржей в июле 2019 года для листинга компаний в таких отраслях, как информационные технологии нового поколения, биомедицина, новая энергетика и охрана окружающей среды. SSE STAR стал одной из крупнейших в мире торговых площадок и ключевой — для китайских компаний-единорогов. За один год, сразу после запуска, 200 компаний из целевого сектора на SSE STAR привлекли около 44 млрд. долларов инвестиций.  
    Комментируя запуск, Джонатан Крейн (Jonathan Krane), генеральный директор KraneShares, сказал: «Мы считаем, что KSTR представляет компании, которые станут будущими лидерами Китая в различных отраслях, которые станут двигателем роста Китая на десятилетия вперед».



    Авто-репост. Читать в блоге >>>
  12. Логотип Interactive Brokers
    InterActiveBrokers, дивиденды: готовим данные для налоговой декларации 3НДФЛ
    Осталось всего несколько дней, чтобы подать налоговую декларацию.
    Для тех счастливчиков, кто получал дивиденды через InterActiveBrokers и немного знаком с Python, выкладываю несколько строк кода, который приведет (почти) данные из Activity-Annual этого брокера в вид, дружелюбный для переноса в российскую декларацию.
    # -*- coding: utf-16 -*-
    import os
    import pandas as pd
    import xml.etree.ElementTree as et
    import lxml.html as lh
    import numpy as np
    #%%
    path_curencies_rates = os.path.join('..//', 'Market_Data')# folder where data is kept
    
    # RUB against USD and EUR
    rub_USD_2020 = 'USD_RUB_exchange_rate_20200101-20201231.xlsx'
    rub_EUR_2020 = 'EUR_RUB_exchange_rate_20200101-20201231.xlsx'
    # dataframe where indicies are dates of 2020 and columns are rates RUB_USD and RUB_EUR
    # all dates of 2020
    dates = pd.date_range(start='1/1/2020', end='12/31/2020')
    rub_currencies_rates = pd.DataFrame(index=dates, columns=['EUR', 'USD'])
    # USD
    df_rub_USD_CBRF = pd.read_excel(os.path.join(path_curencies_rates, rub_USD_2020), index_col=1)
    df_rub_USD_CBRF = df_rub_USD_CBRF[['curs']]
    # EUR
    df_rub_EUR_CBRF = pd.read_excel(os.path.join(path_curencies_rates, rub_EUR_2020), index_col=1)
    df_rub_EUR_CBRF = df_rub_EUR_CBRF[['curs']]
    
    rub_currencies_rates.USD = df_rub_USD_CBRF.curs
    rub_currencies_rates.EUR = df_rub_EUR_CBRF.curs
    
    # fill empty dates
    rub_currencies_rates.EUR = pd.DataFrame.ffill(rub_currencies_rates.EUR)
    rub_currencies_rates.USD = pd.DataFrame.ffill(rub_currencies_rates.USD)
    <br /><br />#%%
    annual_activity_statement = 'Activity-Annual_2020_2020.htm' 
    table_name = 'Dividends' # table that contains dividends only
    report_full = lh.parse(annual_activity_statement)
    parent = report_full.xpath(".//div[contains(text(), '{}')]".format(table_name))[0].getnext()
    element = parent.getchildren()[0].getchildren()[0]
    html = et.tostring(element)
    div_df = pd.read_html(html)[0]
    div_df.Amount = pd.to_numeric(div_df.Amount, errors='coerce')
    div_df.Date = pd.to_datetime(div_df.Date, errors='coerce').dt.date
    div_df = div_df.dropna(subset=['Date'])
    div_df = div_df[div_df.Amount.notnull()]
    
    # If nominated in EUR, taxation was NOT applyed 
    div_df['Currency'] = np.where(div_df.Description.str.contains('EUR'), 'EUR', 'USD')
    
    div_df['Taxes_paid'] = np.where(div_df.Description.str.contains('EUR'), 0, (div_df.Amount*0.1).round(decimals=2))
    
    eur_rub_dict = rub_currencies_rates.EUR.to_dict()
    usd_rub_dict = rub_currencies_rates.USD.to_dict()
    # eur_rub_dict
    div_EUR = div_df[div_df.Currency=='EUR']
    div_EUR['rate_RUB'] = div_EUR['Date'].map(eur_rub_dict)
    
    div_USD = div_df[div_df.Currency=='USD']
    div_USD['rate_RUB'] = 0
    div_USD['rate_RUB'] = div_USD['Date'].map(usd_rub_dict)#rub_currencies_rates.USD
    
    div_total = pd.concat([div_EUR, div_USD], axis=0)
    
    div_total['RUS_tax'] = div_total.Amount * 0.13
    div_total['Taxes_TO_pay'] = ((div_total.RUS_tax - div_total.Taxes_paid) * div_total.rate_RUB).round(decimals=2)
    
    div_total.Taxes_TO_pay.sum().round(decimals=1)
    
    div_total.Description = div_total.Description.str.split(' Cash').str[0]
    
    for i, d in div_total.Date.iteritems():
        ds = d.strftime('%d.%m.%Y')
        div_total.at[i, 'Date'] = ds
    
    #%%
    # To fill in field `'ОКСМ'` of Rus Tax Form ISIN will be used, 
    # it consists of two alphabetic characters, which are the ISO 3166-1 alpha-2 code for the issuing country. 
    # DataBase is `'country_ISO_codes.csv'`
    country_codes = pd.read_csv('country_ISO_codes.csv')
    country_codes = dict(zip(country_codes['alpha-2'], country_codes['country-code']))
    
    def assign_country_code(name, country_codes):
        '''
        Returns a country numeric ICO code.
        Two first symbols of ISIN represent Country ISO-3166 Alpha Code.
        Parameters:
            name : string, field Description from IBKR report;
            country_codes : dictionary, keys are ISO Alpha Codes, values are corresponding ISO Num Codes.
            
        '''
        if '(' and ')' in name:
            start = name.find('(') + 1
            end = name.find(')')
            isin = name[start : end]
            country_Alpha_code = isin[0:2]
            try:
                country_Num_code = country_codes[country_Alpha_code]
            except Exception as e:
                country_Num_code = name
            
            return country_Num_code
        
        return name
    
    div_total['Country_Num_Code'] = div_total['Description'].apply(assign_country_code, country_codes=country_codes)
    
    #%%
    # get all attributes of Rus Tax Form as a list
    path_to_form = 'Tax_form_2020_draft_20210419.xml'
    tree = et.parse(path_to_form)
    root = tree.getroot()
    for el in root.iter('ДоходИстИно'):
        for child in el[0:1]:
            attributes_Rus_Tax_Form = list(child.attrib.keys())
    
    # DataFrame Rus Tax Form with indices from div_total
    df_rus_tax_form = pd.DataFrame(index=div_total.index, columns=attributes_Rus_Tax_Form)
    # fill all fields in with data from corresponing columns
    # do some calculations as well
    df_rus_tax_form['ОКСМ'] = div_total.Country_Num_Code
    df_rus_tax_form['НаимИстДох'] = div_total.Description
    df_rus_tax_form['КодВалют'] = np.where(div_total.Currency=='EUR', '978', '840')
    df_rus_tax_form['КодВидДох'] = '22' # check it out
    df_rus_tax_form['КурсВалютДох'] = div_total.rate_RUB
    df_rus_tax_form['ДатаДох'] = div_total.Date
    df_rus_tax_form['ДатаУплНал'] = div_total.Date
    df_rus_tax_form['ДоходИноВал'] = div_total.Amount
    df_rus_tax_form['ДоходИноРуб'] = (df_rus_tax_form['ДоходИноВал'] * df_rus_tax_form['КурсВалютДох']).round(decimals=2)
    df_rus_tax_form['КурсВалютНал'] = div_total.rate_RUB
    df_rus_tax_form['НалУплИноВал'] = div_total.Taxes_paid
    df_rus_tax_form['НалУплИноРуб'] = (df_rus_tax_form['НалУплИноВал'] * df_rus_tax_form['КурсВалютДох']).round(decimals=2)
    df_rus_tax_form['НалЗачРФОбщ'] = (df_rus_tax_form['ДоходИноРуб'] * 0.13).astype(int)
    df_rus_tax_form['НалогЗачРФОбщ'] = df_rus_tax_form['НалУплИноРуб'].astype(int)
    
    # all data in a xml-object should be str
    form_to_export = df_rus_tax_form.applymap(str)
    
    # create a root
    income_abroad = et.Element('ДоходИстИно')
    tree = et.ElementTree(income_abroad)
    
    # add children with a relevant tag 
    # each child has attributes that is a dict representing a row from DataFrame
    for i, r in form_to_export.iterrows():
        d = r.to_dict()
        et.SubElement(income_abroad, tag='РасчДохНалИно', attrib=d)    
    
    tree.write('rus_tax_form_experiment.xml', encoding='WINDOWS-1251')
    
    
    
    Файлы 
    USD_RUB_exchange_rate_20200101-20201231.xlsx
    EUR_RUB_exchange_rate_20200101-20201231.xlsx
    можно скачать с сайта ЦБ.
    Tax_form_2020_draft_20210419.xml — моя 3-НДФЛ, сохраненная из налогового личного кабинета. 
    country_ISO_codes.csv — коды стран, файлом могу поделиться.

    За критику и правки буду благодарен.

    Авто-репост. Читать в блоге >>>
  13. Логотип Налогообложение на рынке ценных бумаг
    InterActiveBrokers, дивиденды: готовим данные для налоговой декларации 3НДФЛ
    Осталось всего несколько дней, чтобы подать налоговую декларацию.
    Для тех счастливчиков, кто получал дивиденды через InterActiveBrokers и немного знаком с Python, выкладываю несколько строк кода, который приведет (почти) данные из Activity-Annual этого брокера в вид, дружелюбный для переноса в российскую декларацию.
    # -*- coding: utf-16 -*-
    import os
    import pandas as pd
    import xml.etree.ElementTree as et
    import lxml.html as lh
    import numpy as np
    #%%
    path_curencies_rates = os.path.join('..//', 'Market_Data')# folder where data is kept
    
    # RUB against USD and EUR
    rub_USD_2020 = 'USD_RUB_exchange_rate_20200101-20201231.xlsx'
    rub_EUR_2020 = 'EUR_RUB_exchange_rate_20200101-20201231.xlsx'
    # dataframe where indicies are dates of 2020 and columns are rates RUB_USD and RUB_EUR
    # all dates of 2020
    dates = pd.date_range(start='1/1/2020', end='12/31/2020')
    rub_currencies_rates = pd.DataFrame(index=dates, columns=['EUR', 'USD'])
    # USD
    df_rub_USD_CBRF = pd.read_excel(os.path.join(path_curencies_rates, rub_USD_2020), index_col=1)
    df_rub_USD_CBRF = df_rub_USD_CBRF[['curs']]
    # EUR
    df_rub_EUR_CBRF = pd.read_excel(os.path.join(path_curencies_rates, rub_EUR_2020), index_col=1)
    df_rub_EUR_CBRF = df_rub_EUR_CBRF[['curs']]
    
    rub_currencies_rates.USD = df_rub_USD_CBRF.curs
    rub_currencies_rates.EUR = df_rub_EUR_CBRF.curs
    
    # fill empty dates
    rub_currencies_rates.EUR = pd.DataFrame.ffill(rub_currencies_rates.EUR)
    rub_currencies_rates.USD = pd.DataFrame.ffill(rub_currencies_rates.USD)
    <br /><br />#%%
    annual_activity_statement = 'Activity-Annual_2020_2020.htm' 
    table_name = 'Dividends' # table that contains dividends only
    report_full = lh.parse(annual_activity_statement)
    parent = report_full.xpath(".//div[contains(text(), '{}')]".format(table_name))[0].getnext()
    element = parent.getchildren()[0].getchildren()[0]
    html = et.tostring(element)
    div_df = pd.read_html(html)[0]
    div_df.Amount = pd.to_numeric(div_df.Amount, errors='coerce')
    div_df.Date = pd.to_datetime(div_df.Date, errors='coerce').dt.date
    div_df = div_df.dropna(subset=['Date'])
    div_df = div_df[div_df.Amount.notnull()]
    
    # If nominated in EUR, taxation was NOT applyed 
    div_df['Currency'] = np.where(div_df.Description.str.contains('EUR'), 'EUR', 'USD')
    
    div_df['Taxes_paid'] = np.where(div_df.Description.str.contains('EUR'), 0, (div_df.Amount*0.1).round(decimals=2))
    
    eur_rub_dict = rub_currencies_rates.EUR.to_dict()
    usd_rub_dict = rub_currencies_rates.USD.to_dict()
    # eur_rub_dict
    div_EUR = div_df[div_df.Currency=='EUR']
    div_EUR['rate_RUB'] = div_EUR['Date'].map(eur_rub_dict)
    
    div_USD = div_df[div_df.Currency=='USD']
    div_USD['rate_RUB'] = 0
    div_USD['rate_RUB'] = div_USD['Date'].map(usd_rub_dict)#rub_currencies_rates.USD
    
    div_total = pd.concat([div_EUR, div_USD], axis=0)
    
    div_total['RUS_tax'] = div_total.Amount * 0.13
    div_total['Taxes_TO_pay'] = ((div_total.RUS_tax - div_total.Taxes_paid) * div_total.rate_RUB).round(decimals=2)
    
    div_total.Taxes_TO_pay.sum().round(decimals=1)
    
    div_total.Description = div_total.Description.str.split(' Cash').str[0]
    
    for i, d in div_total.Date.iteritems():
        ds = d.strftime('%d.%m.%Y')
        div_total.at[i, 'Date'] = ds
    
    #%%
    # To fill in field `'ОКСМ'` of Rus Tax Form ISIN will be used, 
    # it consists of two alphabetic characters, which are the ISO 3166-1 alpha-2 code for the issuing country. 
    # DataBase is `'country_ISO_codes.csv'`
    country_codes = pd.read_csv('country_ISO_codes.csv')
    country_codes = dict(zip(country_codes['alpha-2'], country_codes['country-code']))
    
    def assign_country_code(name, country_codes):
        '''
        Returns a country numeric ICO code.
        Two first symbols of ISIN represent Country ISO-3166 Alpha Code.
        Parameters:
            name : string, field Description from IBKR report;
            country_codes : dictionary, keys are ISO Alpha Codes, values are corresponding ISO Num Codes.
            
        '''
        if '(' and ')' in name:
            start = name.find('(') + 1
            end = name.find(')')
            isin = name[start : end]
            country_Alpha_code = isin[0:2]
            try:
                country_Num_code = country_codes[country_Alpha_code]
            except Exception as e:
                country_Num_code = name
            
            return country_Num_code
        
        return name
    
    div_total['Country_Num_Code'] = div_total['Description'].apply(assign_country_code, country_codes=country_codes)
    
    #%%
    # get all attributes of Rus Tax Form as a list
    path_to_form = 'Tax_form_2020_draft_20210419.xml'
    tree = et.parse(path_to_form)
    root = tree.getroot()
    for el in root.iter('ДоходИстИно'):
        for child in el[0:1]:
            attributes_Rus_Tax_Form = list(child.attrib.keys())
    
    # DataFrame Rus Tax Form with indices from div_total
    df_rus_tax_form = pd.DataFrame(index=div_total.index, columns=attributes_Rus_Tax_Form)
    # fill all fields in with data from corresponing columns
    # do some calculations as well
    df_rus_tax_form['ОКСМ'] = div_total.Country_Num_Code
    df_rus_tax_form['НаимИстДох'] = div_total.Description
    df_rus_tax_form['КодВалют'] = np.where(div_total.Currency=='EUR', '978', '840')
    df_rus_tax_form['КодВидДох'] = '22' # check it out
    df_rus_tax_form['КурсВалютДох'] = div_total.rate_RUB
    df_rus_tax_form['ДатаДох'] = div_total.Date
    df_rus_tax_form['ДатаУплНал'] = div_total.Date
    df_rus_tax_form['ДоходИноВал'] = div_total.Amount
    df_rus_tax_form['ДоходИноРуб'] = (df_rus_tax_form['ДоходИноВал'] * df_rus_tax_form['КурсВалютДох']).round(decimals=2)
    df_rus_tax_form['КурсВалютНал'] = div_total.rate_RUB
    df_rus_tax_form['НалУплИноВал'] = div_total.Taxes_paid
    df_rus_tax_form['НалУплИноРуб'] = (df_rus_tax_form['НалУплИноВал'] * df_rus_tax_form['КурсВалютДох']).round(decimals=2)
    df_rus_tax_form['НалЗачРФОбщ'] = (df_rus_tax_form['ДоходИноРуб'] * 0.13).astype(int)
    df_rus_tax_form['НалогЗачРФОбщ'] = df_rus_tax_form['НалУплИноРуб'].astype(int)
    
    # all data in a xml-object should be str
    form_to_export = df_rus_tax_form.applymap(str)
    
    # create a root
    income_abroad = et.Element('ДоходИстИно')
    tree = et.ElementTree(income_abroad)
    
    # add children with a relevant tag 
    # each child has attributes that is a dict representing a row from DataFrame
    for i, r in form_to_export.iterrows():
        d = r.to_dict()
        et.SubElement(income_abroad, tag='РасчДохНалИно', attrib=d)    
    
    tree.write('rus_tax_form_experiment.xml', encoding='WINDOWS-1251')
    
    
    
    Файлы 
    USD_RUB_exchange_rate_20200101-20201231.xlsx
    EUR_RUB_exchange_rate_20200101-20201231.xlsx
    можно скачать с сайта ЦБ.
    Tax_form_2020_draft_20210419.xml — моя 3-НДФЛ, сохраненная из налогового личного кабинета. 
    country_ISO_codes.csv — коды стран, файлом могу поделиться.

    За критику и правки буду благодарен.

    Авто-репост. Читать в блоге >>>
Чтобы купить акции, выберите надежного брокера: