[Программирование, Java, Scala, ООП, Функциональное программирование] Программа в 50 строк на Java/Scala, которая сэкономит вам 50 тыс. р. при подаче декларации 3-НДФЛ
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Видео-версия:Извините, данный ресурс не поддреживается. :( Вы, наверное, знаете, с любых доходов нужно платить налоги, в т.ч. с доходов от торговли ценными бумагами и производными инструментами (проще говоря, от игры на бирже). Очень удобно, когда брокер делает расчеты за вас, перед тем как вы выведите деньги со счета, выполняя функции налогового агента.Но если брокер такой как у меня - Interactive Brokers (организация, третьего дня запрещенная на территории РФ), декларацию вам придется делать и подавать самому. Делать это всем, конечно же лень, и неплохо бы отдать подготовку на аутсорс; поэтому в установленный законом срок (до 30.04) я подал нулевую декларацию, и только сейчас озаботился подготовкой уточненки, так как уже скоро нужно платить сам налог.Каково же было мое удивление, когда я узнал расценки на составление у своих товарищей по опасному биржевому бизнесу. Оказалось, что услуги консультантов разнятся от количество проведенных сделок. А количество сделок зависит от того, не болеете ли вы лудоманией (лат. ludo — играю + др.-греч. μανία — безумие, влечение), и не совершаете ли внутри дня множество хаотичных сделок, закармливая брокера комиссией. В США, FINRA пытается остудить горячую голову лудоманов с помощью т.н. Pattern day trader rule, когда лудоман убил свой счет до $25K им блокируют сделки.Так вот, мои товарищи умудрились довести сумму за подготовку декларации до 50 и более тысяч рублей. У меня дела шли не настолько хорошо, чтобы платить такие конские суммы нахлебникам (можете ознакомиться с моей прошлой заметкой "Мой маржин-кол: как теряют деньги на бирже"). Поэтому я решил изучить вопрос и сделать все самостоятельно, по инструкциям, представленным в интернете.
Официальная программа для ввода сумм доходов в декларациюКроме этой программы, есть еще веб-версия, но она совсем неудобна, и мне совершенно не улыбалось вбивать ничего вручную даже в десктопное приложение. На выходе из этой программы, получается xml, который, как я быстро сообразил, можно сгенерить автоматически. В первой его части имеются итоги, которые можно поправить и в блокноте, а окончание выглядит вот так:...<ДоходИстИно Ставка="13"> <РасчДохНалИно ОКСМ="840" НаимИстДох="BFT WS" КодВалют="840" КодВидДох="32" ДатаДох="09.12.2020" КурсВалютДох="73.6618" ДоходИноВал="219.81" ДоходИноРуб="16191.70" НалЗачРФОбщ="893"/>... </ДоходИстИно> <ДохОперЦБ ВидОпер="01" ДохСовОпер="0.00" РасхРеалЦБ="41.15" РасхУмДохОпер="41.15" ПризУчетУбыт="0"/> <ДохОперЦБ ВидОпер="06" ДохСовОпер="500.15" РасхРеалЦБ="42.52" РасхУмДохОпер="42.52" ПризУчетУбыт="0"/> </НДФЛ3></Документ></Файл>Разные инструкции рекомендовали примерно одно и то же - умножить поле "Реализованная П/У" из отчета брокера на дату сделки, и вколотить эти цифры в строки. Были правда и такие, которые предлагали переводить стоимость активов на дату покупки также в рубли, и организовать отдельный суммовой учет по ФИФО, или по средней себестоимости; кто-то считал, что в отчет должна вноситься выручка. Как при этом учитывать коротки позиции, было не понятно, и непонятно, как всю это ерунду должен проверять инспектор в налоговой. Кстати, что меня удивило - я не увидел в xml отдельных сумм своих вычетов, они суммируются и выгружаются одной строкой по каждому коду - что серьезно осложнит автоматическую сверку данных, даже если налоговая захочет это проделать. Поэтому я решил не умничать, а считать доходом то, что считает им брокер (в итоге все равно алгоритмы сойдутся к примерно тому же результату). Брокер IB дает csv такой структуры:
Для формирования собственного xml я написал вот такую программу, которая получилась довольно небольшой, поэтому она могла бы послужить кому-то примером для обучения :
import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory
import java.io.PrintWriter
import java.nio.charset.Charset
import java.text.DecimalFormatSymbols
import java.util.Locale
import scala.io.Source
object Tax {
def main(args: Array[String]): Unit = {
implicit val logger = Logger(LoggerFactory.getLogger(this.getClass))
import java.text.DecimalFormat
val df = new DecimalFormat("0.00")
val dfRate = new DecimalFormat("0.0000")
df.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ENGLISH))
dfRate.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ENGLISH))
val str = (Source.fromFile("d:\\tax\\1.csv","UTF-8").getLines().toSeq ++ Source.fromFile("d:\\tax\\2.csv","UTF-8").getLines().toSeq)
.map(_.split(",(?=(?:[^"]*"[^"]*")*[^"]*$)", -1).toList)
val rates = Source.fromFile("d:\\tax\\r.csv","windows-1252").getLines().map(_.split(';')).toSeq
.map(e1=>e1.updated(1,e1(1).split('.').reverse.mkString("-")))
def rate(d:String)={
rates.sortBy(_(1)).findLast(e=>e(1)<=d).map{x=>
if (x(1)!=d) logger.debug(s"Нет курса на дату $d, последний ${x(1)}")
BigDecimal(x(2).replaceAll(",","."))
}.get
}
val str1 = str.filter(_.length > 15).filter(e => e(0) == "Сделки" && e(1) == "Data").filter{e=> e(13)!=""}
.map(e=>(e,{
val date = e(6).replaceAll(""","" ).split(',')(0)
val rt = rate(date)
val sumR = (rt * BigDecimal(e(13)))
val codes = e(3).trim match {
case "Контракты на разницу (CFD)" => ("893","06")//1532
case "Опционы на акции и индексы" => ("893","06")//1532
case "Варранты" => ("893","06")//1532
case "Акции" => ("79","01")//1530
}
val xml = s"""<РасчДохНалИно ОКСМ="840" НаимИстДох="${e(5)}" КодВалют="840" КодВидДох="32" ДатаДох="${
date.split('-').reverse.mkString(".")
}" КурсВалютДох="${dfRate.format(rt)}" ДоходИноВал="${df.format(BigDecimal(e(13)))}" ДоходИноРуб="${df.format(sumR)}" НалЗачРФОбщ="${codes._1}"/>"""
(xml,sumR,codes)
}))
val txt = str1.filter(_._2._2>0).map(_._2._1).mkString("") +
str1.groupBy(_._2._3).map(e=>(e._1,{
val x = e._2.map(_._2._2)
(x.filter(_ >0).sum,-x.filter(_ <0).sum)
})).map(e=>
s"""<ДохОперЦБ ВидОпер="${e._1._2}" ДохСовОпер="${df.format(e._2._1)}" РасхРеалЦБ="${df.format(e._2._2)}" РасхУмДохОпер="${df.format(e._2._2)}" ПризУчетУбыт="0"/>"""
).mkString("\n") match {
case e=> new PrintWriter("d:\\tax\\tax_xml.txt", Charset.forName("UTF-8")) { write(e); close }
}
logger.debug(s"Дох=${str1.map(e=>e._2._2).filter(_ >0 ).sum} " +
s"Расх=${str1.map(e=>e._2._2).filter(_ <0 ).sum}" +
s"База=${str1.map(e=>e._2._2).sum}")
}
}
Несколько комментариев по коду:
- В программе конкатенируется несколько файлов, потому что при торговле CFD используется отдельный субсчет, на который автоматически скидываются деньги, отчет по нему отдельный.
- Американский формат дат типа "2020-12-24" позволяет сортировать даты для быстрого нахождения последнего курса на дату (файл ЦБ не содержит курсов в пн. и по праздникам), поэтому пришлось привести данные к этому формату.
- Наличие в файле кавычек не позволяет делать split(','), требуется использовать regexp.
Почему я заикнулся о том, что этот мой лапшекод (design pattern, all rights reserved) с захардкоженными именами файла и прочими нелицеприятным решениями, можно использовать для обучения? Во-первых, что начинающий программист в первую очередь должен уметь читать и поддерживать чужой код, написанный на скорую руку. Если он неспособен разобраться даже в такой программке, очевидно, что в боевой обстановке он растеряется еще больше.А во-вторых, все мы когда-то мечтали что будем запускать ракеты на Марс, или писать игры категории triple-A, а на самом деле, производственные задачи - вещь намного более скучная, это в основном бухучет, 1С, SAP, либо с случае банков, java/scala, таблицы Excel, запросы SQL, генерация xml и json. Чем раньше у начинающего программиста развеятся вредные иллюзии, тем лучше. Поэтому, думаю, даже если вы не торгуете у зарубежных брокеров, и вам не надо сдавать 3-НДФЛ, данная заметка может быть интересной и для вас.
===========
Источник:
habr.com
===========
Похожие новости:
- [C++, Программирование микроконтроллеров] Использование coroutines из С++20 в связке с NRF52832 и GTest
- [Программирование, Функциональное программирование, Визуализация данных, Kotlin, Разработка под Linux] Продолжаем обрабатывать NDJSON
- [Программирование микроконтроллеров, DIY или Сделай сам, Звук] Как пьезоизлучатель голос искал
- [Программирование, Геоинформационные сервисы, Математика, Научно-популярное, Физика] Кто и как поломал Землю, или откуда возникли планетарные горные хребты и разломы
- [Open source, Программирование, Учебный процесс в IT] Как я учил студентов Северной Кореи разрабатывать ПО с открытым исходным кодом (перевод)
- [JavaScript, ReactJS] 5 причин использовать LesnJs
- [Программирование, Java] Вилкой в глаз, или ForkJoinPool в Java
- [Программирование, .NET] Creating a NuGet package for a library with platform-specific API
- [JavaScript, ReactJS] Почему иногда React/Redux в текущем состоянии give me creeps
- [Программирование, Cobol, Карьера в IT-индустрии, История IT, Старое железо] Исследование: компании столкнулись с проблемой передачи опыта старых технологий новым работникам
Теги для поиска: #_programmirovanie (Программирование), #_java, #_scala, #_oop (ООП), #_funktsionalnoe_programmirovanie (Функциональное программирование), #_programma_java (программа java), #_scala, #_trejding (трейдинг), #_trejding_na_fondovom_rynke (трейдинг на фондовом рынке), #_buhuchet (бухучет), #_ndfl (ндфл), #_birzha (биржа), #_birzhevaja_torgovlja (биржевая торговля), #_birzhevoj_soft (биржевой софт), #_birzhi_raboty (биржи работы), #_programmirovanie (
Программирование
), #_java, #_scala, #_oop (
ООП
), #_funktsionalnoe_programmirovanie (
Функциональное программирование
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:47
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Видео-версия:Извините, данный ресурс не поддреживается. :( Вы, наверное, знаете, с любых доходов нужно платить налоги, в т.ч. с доходов от торговли ценными бумагами и производными инструментами (проще говоря, от игры на бирже). Очень удобно, когда брокер делает расчеты за вас, перед тем как вы выведите деньги со счета, выполняя функции налогового агента.Но если брокер такой как у меня - Interactive Brokers (организация, третьего дня запрещенная на территории РФ), декларацию вам придется делать и подавать самому. Делать это всем, конечно же лень, и неплохо бы отдать подготовку на аутсорс; поэтому в установленный законом срок (до 30.04) я подал нулевую декларацию, и только сейчас озаботился подготовкой уточненки, так как уже скоро нужно платить сам налог.Каково же было мое удивление, когда я узнал расценки на составление у своих товарищей по опасному биржевому бизнесу. Оказалось, что услуги консультантов разнятся от количество проведенных сделок. А количество сделок зависит от того, не болеете ли вы лудоманией (лат. ludo — играю + др.-греч. μανία — безумие, влечение), и не совершаете ли внутри дня множество хаотичных сделок, закармливая брокера комиссией. В США, FINRA пытается остудить горячую голову лудоманов с помощью т.н. Pattern day trader rule, когда лудоман убил свой счет до $25K им блокируют сделки.Так вот, мои товарищи умудрились довести сумму за подготовку декларации до 50 и более тысяч рублей. У меня дела шли не настолько хорошо, чтобы платить такие конские суммы нахлебникам (можете ознакомиться с моей прошлой заметкой "Мой маржин-кол: как теряют деньги на бирже"). Поэтому я решил изучить вопрос и сделать все самостоятельно, по инструкциям, представленным в интернете. Официальная программа для ввода сумм доходов в декларациюКроме этой программы, есть еще веб-версия, но она совсем неудобна, и мне совершенно не улыбалось вбивать ничего вручную даже в десктопное приложение. На выходе из этой программы, получается xml, который, как я быстро сообразил, можно сгенерить автоматически. В первой его части имеются итоги, которые можно поправить и в блокноте, а окончание выглядит вот так:...<ДоходИстИно Ставка="13"> <РасчДохНалИно ОКСМ="840" НаимИстДох="BFT WS" КодВалют="840" КодВидДох="32" ДатаДох="09.12.2020" КурсВалютДох="73.6618" ДоходИноВал="219.81" ДоходИноРуб="16191.70" НалЗачРФОбщ="893"/>... </ДоходИстИно> <ДохОперЦБ ВидОпер="01" ДохСовОпер="0.00" РасхРеалЦБ="41.15" РасхУмДохОпер="41.15" ПризУчетУбыт="0"/> <ДохОперЦБ ВидОпер="06" ДохСовОпер="500.15" РасхРеалЦБ="42.52" РасхУмДохОпер="42.52" ПризУчетУбыт="0"/> </НДФЛ3></Документ></Файл>Разные инструкции рекомендовали примерно одно и то же - умножить поле "Реализованная П/У" из отчета брокера на дату сделки, и вколотить эти цифры в строки. Были правда и такие, которые предлагали переводить стоимость активов на дату покупки также в рубли, и организовать отдельный суммовой учет по ФИФО, или по средней себестоимости; кто-то считал, что в отчет должна вноситься выручка. Как при этом учитывать коротки позиции, было не понятно, и непонятно, как всю это ерунду должен проверять инспектор в налоговой. Кстати, что меня удивило - я не увидел в xml отдельных сумм своих вычетов, они суммируются и выгружаются одной строкой по каждому коду - что серьезно осложнит автоматическую сверку данных, даже если налоговая захочет это проделать. Поэтому я решил не умничать, а считать доходом то, что считает им брокер (в итоге все равно алгоритмы сойдутся к примерно тому же результату). Брокер IB дает csv такой структуры: Для формирования собственного xml я написал вот такую программу, которая получилась довольно небольшой, поэтому она могла бы послужить кому-то примером для обучения : import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory import java.io.PrintWriter import java.nio.charset.Charset import java.text.DecimalFormatSymbols import java.util.Locale import scala.io.Source object Tax { def main(args: Array[String]): Unit = { implicit val logger = Logger(LoggerFactory.getLogger(this.getClass)) import java.text.DecimalFormat val df = new DecimalFormat("0.00") val dfRate = new DecimalFormat("0.0000") df.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ENGLISH)) dfRate.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ENGLISH)) val str = (Source.fromFile("d:\\tax\\1.csv","UTF-8").getLines().toSeq ++ Source.fromFile("d:\\tax\\2.csv","UTF-8").getLines().toSeq) .map(_.split(",(?=(?:[^"]*"[^"]*")*[^"]*$)", -1).toList) val rates = Source.fromFile("d:\\tax\\r.csv","windows-1252").getLines().map(_.split(';')).toSeq .map(e1=>e1.updated(1,e1(1).split('.').reverse.mkString("-"))) def rate(d:String)={ rates.sortBy(_(1)).findLast(e=>e(1)<=d).map{x=> if (x(1)!=d) logger.debug(s"Нет курса на дату $d, последний ${x(1)}") BigDecimal(x(2).replaceAll(",",".")) }.get } val str1 = str.filter(_.length > 15).filter(e => e(0) == "Сделки" && e(1) == "Data").filter{e=> e(13)!=""} .map(e=>(e,{ val date = e(6).replaceAll(""","" ).split(',')(0) val rt = rate(date) val sumR = (rt * BigDecimal(e(13))) val codes = e(3).trim match { case "Контракты на разницу (CFD)" => ("893","06")//1532 case "Опционы на акции и индексы" => ("893","06")//1532 case "Варранты" => ("893","06")//1532 case "Акции" => ("79","01")//1530 } val xml = s"""<РасчДохНалИно ОКСМ="840" НаимИстДох="${e(5)}" КодВалют="840" КодВидДох="32" ДатаДох="${ date.split('-').reverse.mkString(".") }" КурсВалютДох="${dfRate.format(rt)}" ДоходИноВал="${df.format(BigDecimal(e(13)))}" ДоходИноРуб="${df.format(sumR)}" НалЗачРФОбщ="${codes._1}"/>""" (xml,sumR,codes) })) val txt = str1.filter(_._2._2>0).map(_._2._1).mkString("") + str1.groupBy(_._2._3).map(e=>(e._1,{ val x = e._2.map(_._2._2) (x.filter(_ >0).sum,-x.filter(_ <0).sum) })).map(e=> s"""<ДохОперЦБ ВидОпер="${e._1._2}" ДохСовОпер="${df.format(e._2._1)}" РасхРеалЦБ="${df.format(e._2._2)}" РасхУмДохОпер="${df.format(e._2._2)}" ПризУчетУбыт="0"/>""" ).mkString("\n") match { case e=> new PrintWriter("d:\\tax\\tax_xml.txt", Charset.forName("UTF-8")) { write(e); close } } logger.debug(s"Дох=${str1.map(e=>e._2._2).filter(_ >0 ).sum} " + s"Расх=${str1.map(e=>e._2._2).filter(_ <0 ).sum}" + s"База=${str1.map(e=>e._2._2).sum}") } }
=========== Источник: habr.com =========== Похожие новости:
Программирование ), #_java, #_scala, #_oop ( ООП ), #_funktsionalnoe_programmirovanie ( Функциональное программирование ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:47
Часовой пояс: UTC + 5