コード例 #1
0
ファイル: ledger.py プロジェクト: uMag/ledger
 def processActionDetails(self):
     query = executeSQL(
         self.db,
         "SELECT sum as amount, category_id, tag_id FROM action_details AS d WHERE pid=:pid",
         [(":pid", self.current[OPERATION_ID])])
     while query.next():
         amount, self.current[PRICE_CATEGORY], self.current[
             FEE_TAX_TAG] = readSQLrecord(query)
         book = BookAccount.Costs if amount < 0 else BookAccount.Incomes
         self.appendTransaction(book, -amount)
コード例 #2
0
ファイル: taxes.py プロジェクト: uMag/ledger
    def prepare_broker_fees(self, sheet, account_id, begin, end, formats):
        self.add_report_header(sheet, formats, "Отчет по комиссиям, уплаченным брокеру в отчетном периоде")

        _ = executeSQL(self.db, "DELETE FROM t_last_dates")
        _ = executeSQL(self.db,
                       "INSERT INTO t_last_dates(ref_id, timestamp) "
                       "SELECT a.id AS ref_id, MAX(q.timestamp) AS timestamp "
                       "FROM actions AS a "
                       "LEFT JOIN accounts AS c ON c.id = :account_id "
                       "LEFT JOIN quotes AS q ON a.timestamp >= q.timestamp AND c.currency_id=q.asset_id "
                       "LEFT JOIN action_details AS d ON d.pid=a.id "
                       "WHERE a.timestamp>=:begin AND a.timestamp<:end "
                       "AND a.account_id=:account_id AND d.note LIKE '%MONTHLY%' "
                       "GROUP BY a.id",
                       [(":begin", begin), (":end", end), (":account_id", account_id)])
        self.db.commit()

        header_row = {
            0: ("Описание", formats.ColumnHeader(), 50, 0, 0),
            1: ("Сумма, USD", formats.ColumnHeader(), 8, 0, 0),
            2: ("Дата оплаты", formats.ColumnHeader(), 10, 0, 0),
            3: ("Курс USD/RUB на дату оплаты", formats.ColumnHeader(), 10, 0, 0),
            4: ("Сумма, RUB", formats.ColumnHeader(), 10, 0, 0)
        }
        xlsxWriteRow(sheet, 7, header_row, 60)
        for column in range(len(header_row)):  # Put column numbers for reference
            header_row[column] = (f"({column + 1})", formats.ColumnHeader())
        xlsxWriteRow(sheet, 8, header_row)

        query = executeSQL(self.db,
                           "SELECT a.timestamp AS payment_date, d.sum AS amount, d.note AS note, q.quote AS rate_cbr "
                           "FROM actions AS a "
                           "LEFT JOIN action_details AS d ON d.pid=a.id "
                           "LEFT JOIN accounts AS c ON c.id = :account_id "
                           "LEFT JOIN t_last_dates AS ld ON a.id=ld.ref_id "
                           "LEFT JOIN quotes AS q ON ld.timestamp=q.timestamp AND c.currency_id=q.asset_id "
                           "WHERE a.timestamp>=:begin AND a.timestamp<:end "
                           "AND a.account_id=:account_id AND d.note LIKE '%MONTHLY%' ",
                           [(":begin", begin), (":end", end), (":account_id", account_id)])
        row = 9
        amount_rub_sum = 0
        while query.next():
            payment_date, amount, note, rate = readSQLrecord(query)
            amount_rub = round(-amount * rate, 2)
            xlsxWriteRow(sheet, row, {
                0: (note, formats.Text(row)),
                1: (-amount, formats.Number(row, 2)),
                2: (datetime.fromtimestamp(payment_date).strftime('%d.%m.%Y'), formats.Text(row)),
                3: (rate, formats.Number(row, 4)),
                4: (amount_rub, formats.Number(row, 2))
            })
            amount_rub_sum += amount_rub
            row += 1
        sheet.write(row, 3, "ИТОГО", formats.ColumnFooter())
        sheet.write(row, 4, amount_rub_sum, formats.ColumnFooter())
コード例 #3
0
 def prepareIncomeSpendingReport(self, begin, end, account_id, group_dates):
     _ = executeSQL(self.db, "DELETE FROM t_months")
     _ = executeSQL(self.db, "DELETE FROM t_pivot")
     _ = executeSQL(
         self.db, "INSERT INTO t_months (month, asset_id, last_timestamp) "
         "SELECT strftime('%s', datetime(timestamp, 'unixepoch', 'start of month') ) "
         "AS month, asset_id, MAX(timestamp) AS last_timestamp "
         "FROM quotes AS q "
         "LEFT JOIN assets AS a ON q.asset_id=a.id "
         "WHERE a.type_id=:asset_money "
         "GROUP BY month, asset_id",
         [(":asset_money", PredefinedAsset.Money)])
     _ = executeSQL(
         self.db, "INSERT INTO t_pivot (row_key, col_key, value) "
         "SELECT strftime('%s', datetime(t.timestamp, 'unixepoch', 'start of month') ) AS row_key, "
         "t.category_id AS col_key, sum(-t.amount * coalesce(q.quote, 1)) AS value "
         "FROM ledger AS t "
         "LEFT JOIN t_months AS d ON row_key = d.month AND t.asset_id = d.asset_id "
         "LEFT JOIN quotes AS q ON d.last_timestamp = q.timestamp AND t.asset_id = q.asset_id "
         "WHERE (t.book_account=:book_costs OR t.book_account=:book_incomes) "
         "AND t.timestamp>=:begin AND t.timestamp<=:end "
         "GROUP BY row_key, col_key",
         [(":book_costs", BookAccount.Costs),
          (":book_incomes", BookAccount.Incomes), (":begin", begin),
          (":end", end)])
     self.db.commit()
     self.query = executeSQL(
         self.db, "SELECT c.id, c.level, c.path, "
         "strftime('%Y', datetime(p.row_key, 'unixepoch')) AS year, "
         "strftime('%m', datetime(p.row_key, 'unixepoch')) AS month, p.value "
         "FROM categories_tree AS c "
         "LEFT JOIN t_pivot AS p ON p.col_key=c.id "
         "ORDER BY c.path, year, month")
     table = []
     while self.query.next():
         id, level, category, year, month, value = readSQLrecord(self.query)
         turnover = value if value != '' else 0
         table.append({
             'category': category,
             'Y': year,
             'M': month,
             'turnover': turnover
         })
     data = pd.DataFrame(table)
     data = pd.pivot_table(data,
                           index=['category'],
                           columns=['Y', 'M'],
                           values=['turnover'],
                           aggfunc=sum,
                           fill_value=0.0,
                           margins=True,
                           margins_name=g_tr('Reports', "TOTAL"))
     if data.columns[0][
             1] == '':  # if some categories have no data and we have null 1st column
         data = data.drop(columns=[data.columns[0]])
     # Calculate sub-totals from bottom to top
     totals = {}
     prev_level = 0
     for index, row in data[::-1].iterrows():
         if index == g_tr('Reports', "TOTAL"):
             continue
         level = index.count(TREE_LEVEL_SEPARATOR)
         if level > prev_level:
             totals[level] = row['turnover']
             prev_level = level
         elif level == prev_level:
             try:
                 totals[level] = totals[level] + row['turnover']
             except KeyError:
                 totals[level] = row['turnover']
         elif level < prev_level:
             try:
                 totals[level] = totals[level] + totals[prev_level] + row[
                     'turnover']
             except KeyError:
                 totals[level] = totals[prev_level] + row['turnover']
             sub_total = totals.pop(prev_level, None)
             data.loc[index, :] = sub_total.values
             prev_level = level
     self.dataframe = data
     return True
コード例 #4
0
ファイル: ledger.py プロジェクト: uMag/ledger
    def rebuild(self, from_timestamp=-1, fast_and_dirty=False, silent=True):
        operationProcess = {
            TransactionType.Action: self.processAction,
            TransactionType.Dividend: self.processDividend,
            TransactionType.Trade: self.processTrade,
            TransactionType.Transfer: self.processTransfer,
        }

        if from_timestamp >= 0:
            frontier = from_timestamp
            silent = False
        else:
            frontier = self.getCurrentFrontier()
            operations_count = readSQL(
                self.db,
                "SELECT COUNT(id) FROM all_transactions WHERE timestamp >= :frontier",
                [(":frontier", frontier)])
            if operations_count > self.SILENT_REBUILD_THRESHOLD:
                silent = False
                if QMessageBox().warning(
                        None, g_tr('Ledger', "Confirmation"),
                        f"{operations_count}" + g_tr(
                            'Ledger',
                            " operations require rebuild. Do you want to do it right now?"
                        ), QMessageBox.Yes, QMessageBox.No) == QMessageBox.No:
                    return
        if not silent:
            logging.info(
                g_tr('Ledger', "Re-build ledger from: ") +
                f"{datetime.fromtimestamp(frontier).strftime('%d/%m/%Y %H:%M:%S')}"
            )
        start_time = datetime.now()
        _ = executeSQL(
            self.db, "DELETE FROM deals WHERE close_sid >= "
            "(SELECT coalesce(MIN(id), 0) FROM sequence WHERE timestamp >= :frontier)",
            [(":frontier", frontier)])
        _ = executeSQL(self.db,
                       "DELETE FROM ledger WHERE timestamp >= :frontier",
                       [(":frontier", frontier)])
        _ = executeSQL(self.db,
                       "DELETE FROM sequence WHERE timestamp >= :frontier",
                       [(":frontier", frontier)])
        _ = executeSQL(self.db,
                       "DELETE FROM ledger_sums WHERE timestamp >= :frontier",
                       [(":frontier", frontier)])
        self.db.commit()

        if fast_and_dirty:  # For 30k operations difference of execution time is - with 0:02:41 / without 0:11:44
            _ = executeSQL(self.db, "PRAGMA synchronous = OFF")
        query = executeSQL(
            self.db,
            "SELECT type, id, timestamp, subtype, account, currency, asset, amount, "
            "price_category, coupon_peer, fee_tax_tag FROM all_transactions "
            "WHERE timestamp >= :frontier", [(":frontier", frontier)])
        while query.next():
            self.current = readSQLrecord(query)
            seq_query = executeSQL(
                self.db, "INSERT INTO sequence(timestamp, type, operation_id) "
                "VALUES(:timestamp, :type, :operation_id)",
                [(":timestamp", self.current[TIMESTAMP]),
                 (":type", self.current[TRANSACTION_TYPE]),
                 (":operation_id", self.current[OPERATION_ID])])
            self.current_seq = seq_query.lastInsertId()
            operationProcess[self.current[TRANSACTION_TYPE]]()
            if not silent and (query.at() % 1000) == 0:
                logging.info(
                    g_tr('Ledger', "Processed ") + f"{int(query.at()/1000)}" +
                    g_tr('Ledger', "k records, current frontier: ") +
                    f"{datetime.fromtimestamp(self.current[TIMESTAMP]).strftime('%d/%m/%Y %H:%M:%S')}"
                )
        if fast_and_dirty:
            _ = executeSQL(self.db, "PRAGMA synchronous = ON")

        end_time = datetime.now()
        if not silent:
            logging.info(
                g_tr('Ledger', "Ledger is complete. Elapsed time: ") +
                f"{end_time - start_time}" +
                g_tr('Ledger', ", new frontier: ") +
                f"{datetime.fromtimestamp(self.current[TIMESTAMP]).strftime('%d/%m/%Y %H:%M:%S')}"
            )
        self.updateBalancesView()
        self.updateHoldingsView()
コード例 #5
0
ファイル: ledger.py プロジェクト: uMag/ledger
 def processSell(self):
     seq_id = self.current_seq
     account_id = self.current[ACCOUNT_ID]
     asset_id = self.current[ASSET_ID]
     qty = -self.current[AMOUNT_QTY]
     price = self.current[PRICE_CATEGORY]
     trade_value = round(
         price * qty,
         2) - self.current[FEE_TAX_TAG] + self.current[COUPON_PEER]
     buy_qty = 0
     buy_value = 0
     if self.getAmount(BookAccount.Assets, asset_id) > 0:
         query = executeSQL(
             self.db,
             "SELECT d.open_sid AS open, abs(o.qty) - SUM(d.qty) AS remainder FROM deals AS d "
             "LEFT JOIN sequence AS os ON os.type=3 AND os.id=d.open_sid "
             "JOIN trades AS o ON o.id = os.operation_id "
             "WHERE d.account_id=:account_id AND d.asset_id=:asset_id "
             "GROUP BY d.open_sid "
             "ORDER BY d.close_sid DESC, d.open_sid DESC LIMIT 1",
             [(":account_id", account_id), (":asset_id", asset_id)])
         if query.next(
         ):  # sid of Buy trade from last deal and non-matched reminder of last Sell trade
             last_sid, reminder = readSQLrecord(query)
             query = executeSQL(
                 self.db, "SELECT s.id, t.qty, t.price FROM trades AS t "
                 "LEFT JOIN sequence AS s ON s.type = 3 AND s.operation_id=t.id "
                 "WHERE t.qty > 0 AND t.asset_id = :asset_id AND t.account_id = :account_id "
                 "AND s.id < :sid AND s.id >= :last_sid",
                 [(":asset_id", asset_id), (":account_id", account_id),
                  (":sid", seq_id), (":last_sid", last_sid)])
         else:  # There were no deals -> Select all purchases
             reminder = 0
             query = executeSQL(
                 self.db, "SELECT s.id, t.qty, t.price FROM trades AS t "
                 "LEFT JOIN sequence AS s ON s.type = 3 AND s.operation_id=t.id "
                 "WHERE t.qty>0 AND t.asset_id=:asset_id AND t.account_id=:account_id AND s.id<:sid",
                 [(":asset_id", asset_id), (":account_id", account_id),
                  (":sid", seq_id)])
         while query.next():
             deal_sid, deal_qty, deal_price = readSQLrecord(query)
             if reminder > 0:
                 next_deal_qty = reminder
                 reminder = 0
             else:
                 next_deal_qty = deal_qty
             if (
                     buy_qty + next_deal_qty
             ) >= qty:  # we are selling less or the same amount as was bought previously
                 next_deal_qty = qty - buy_qty
             _ = executeSQL(
                 self.db,
                 "INSERT INTO deals(account_id, asset_id, open_sid, close_sid, qty) "
                 "VALUES(:account_id, :asset_id, :open_sid, :close_sid, :qty)",
                 [(":account_id", account_id), (":asset_id", asset_id),
                  (":open_sid", deal_sid), (":close_sid", seq_id),
                  (":qty", next_deal_qty)])
             buy_qty = buy_qty + next_deal_qty
             buy_value = buy_value + (next_deal_qty * deal_price)
             if buy_qty == qty:
                 break
     credit_returned = self.returnCredit(trade_value)
     if credit_returned < trade_value:
         self.appendTransaction(BookAccount.Money,
                                (trade_value - credit_returned))
     if buy_qty > 0:  # Add result of closed deals
         self.appendTransaction(BookAccount.Assets, -buy_qty, -buy_value)
         self.current[PRICE_CATEGORY] = PredefinedCategory.Profit
         self.appendTransaction(BookAccount.Incomes,
                                (buy_value - (price * buy_qty)))
     if buy_qty < qty:  # Add new short position
         self.appendTransaction(BookAccount.Assets, (buy_qty - qty),
                                (buy_qty - qty) * price)
     if self.current[COUPON_PEER]:
         self.current[PRICE_CATEGORY] = PredefinedCategory.Dividends
         self.appendTransaction(BookAccount.Incomes,
                                -self.current[COUPON_PEER])
     if self.current[FEE_TAX_TAG]:
         self.current[PRICE_CATEGORY] = PredefinedCategory.Fees
         self.appendTransaction(BookAccount.Costs,
                                self.current[FEE_TAX_TAG])
コード例 #6
0
ファイル: taxes.py プロジェクト: uMag/ledger
    def prepare_dividends(self, sheet, account_id, begin, end, formats):
        self.add_report_header(sheet, formats, "Отчет по дивидендам, полученным в отчетном периоде")
        _ = executeSQL(self.db, "DELETE FROM t_last_dates")
        _ = executeSQL(self.db,
                       "INSERT INTO t_last_dates(ref_id, timestamp) "
                       "SELECT d.id AS ref_id, MAX(q.timestamp) AS timestamp "
                       "FROM dividends AS d "
                       "LEFT JOIN accounts AS a ON d.account_id=a.id "
                       "LEFT JOIN quotes AS q ON d.timestamp >= q.timestamp AND a.currency_id=q.asset_id "
                       "WHERE d.timestamp>=:begin AND d.timestamp<:end AND d.account_id=:account_id "
                       "GROUP BY d.id", [(":begin", begin), (":end", end), (":account_id", account_id)])
        self.db.commit()

        header_row = {
            0: ("Дата выплаты", formats.ColumnHeader(), 10, 0, 0),
            1: ("Ценная бумага", formats.ColumnHeader(), 8, 0, 0),
            2: ("Полное наименование", formats.ColumnHeader(), 50, 0, 0),
            3: ("Курс USD/RUB на дату выплаты", formats.ColumnHeader(), 16, 0, 0),
            4: ("Доход, USD", formats.ColumnHeader(), 12, 0, 0),
            5: ("Доход, RUB", formats.ColumnHeader(), 12, 0, 0),
            6: ("Налог упл., USD", formats.ColumnHeader(), 12, 0, 0),
            7: ("Налог упл., RUB", formats.ColumnHeader(), 12, 0, 0),
            8: ("Налок к уплате, RUB", formats.ColumnHeader(), 12, 0, 0)
        }
        xlsxWriteRow(sheet, 7, header_row, 30)
        for column in range(len(header_row)):  # Put column numbers for reference
            header_row[column] = (f"({column + 1})", formats.ColumnHeader())
        xlsxWriteRow(sheet, 8, header_row)

        query = executeSQL(self.db,
                           "SELECT d.timestamp AS payment_date, s.name AS symbol, s.full_name AS full_name, "
                           "d.sum AS amount, d.sum_tax AS tax_amount, q.quote AS rate_cbr "
                           "FROM dividends AS d "
                           "LEFT JOIN assets AS s ON s.id = d.asset_id "
                           "LEFT JOIN accounts AS a ON d.account_id = a.id "
                           "LEFT JOIN t_last_dates AS ld ON d.id=ld.ref_id "
                           "LEFT JOIN quotes AS q ON ld.timestamp=q.timestamp AND a.currency_id=q.asset_id "
                           "WHERE d.timestamp>=:begin AND d.timestamp<:end AND d.account_id=:account_id "
                           "ORDER BY d.timestamp",
                           [(":begin", begin), (":end", end), (":account_id", account_id)])
        row = 9
        amount_rub_sum = 0
        amount_usd_sum = 0
        tax_usd_sum = 0
        tax_us_rub_sum = 0
        tax_ru_rub_sum = 0
        while query.next():
            payment_date, symbol, full_name, amount_usd, tax_usd, rate = readSQLrecord(query)
            amount_rub = round(amount_usd * rate, 2)
            tax_us_rub = round(-tax_usd * rate, 2)
            tax_ru_rub = round(0.13 * amount_rub, 2)
            if tax_ru_rub > tax_us_rub:
                tax_ru_rub = tax_ru_rub - tax_us_rub
            else:
                tax_ru_rub = 0
            xlsxWriteRow(sheet, row, {
                0: (datetime.fromtimestamp(payment_date).strftime('%d.%m.%Y'), formats.Text(row)),
                1: (symbol, formats.Text(row)),
                2: (full_name, formats.Text(row)),
                3: (rate, formats.Number(row, 4)),
                4: (amount_usd, formats.Number(row, 2)),
                5: (amount_rub, formats.Number(row, 2)),
                6: (-tax_usd, formats.Number(row, 2)),
                7: (tax_us_rub, formats.Number(row, 2)),
                8: (tax_ru_rub, formats.Number(row, 2))
            })
            amount_usd_sum += amount_usd
            amount_rub_sum += amount_rub
            tax_usd_sum += -tax_usd
            tax_us_rub_sum += tax_us_rub
            tax_ru_rub_sum += tax_ru_rub
            row += 1
        xlsxWriteRow(sheet, row, {
            3: ("ИТОГО", formats.ColumnFooter()),
            4: (amount_usd_sum, formats.ColumnFooter()),
            5: (amount_rub_sum, formats.ColumnFooter()),
            6: (tax_usd_sum, formats.ColumnFooter()),
            7: (tax_us_rub_sum, formats.ColumnFooter()),
            8: (tax_ru_rub_sum, formats.ColumnFooter())
        })
コード例 #7
0
ファイル: taxes.py プロジェクト: uMag/ledger
    def prepare_trades(self, sheet, account_id, begin, end, formats):
        self.add_report_header(sheet, formats, "Отчет по сделкам с ценными бумагами, завершённым в отчетном периоде")
        _ = executeSQL(self.db, "DELETE FROM t_last_dates")
        _ = executeSQL(self.db,
                       "INSERT INTO t_last_dates(ref_id, timestamp) "
                       "SELECT ref_id, MAX(q.timestamp) AS timestamp "
                       "FROM (SELECT o.timestamp AS ref_id "
                       "FROM deals AS d "
                       "LEFT JOIN sequence AS os ON os.id=d.open_sid "
                       "LEFT JOIN trades AS o ON os.operation_id=o.id "
                       "WHERE o.timestamp<:end AND d.account_id=:account_id "
                       "UNION "
                       "SELECT c.timestamp AS ref_id "
                       "FROM deals AS d "
                       "LEFT JOIN sequence AS cs ON cs.id=d.close_sid "
                       "LEFT JOIN trades AS c ON cs.operation_id=c.id "
                       "WHERE c.timestamp<:end AND d.account_id=:account_id "
                       "UNION "
                       "SELECT o.settlement AS ref_id "
                       "FROM deals AS d "
                       "LEFT JOIN sequence AS os ON os.id=d.open_sid "
                       "LEFT JOIN trades AS o ON os.operation_id=o.id "
                       "WHERE o.timestamp<:end AND d.account_id=:account_id "
                       "UNION "
                       "SELECT c.settlement AS ref_id "
                       "FROM deals AS d "
                       "LEFT JOIN sequence AS cs ON cs.id=d.close_sid "
                       "LEFT JOIN trades AS c ON cs.operation_id=c.id "
                       "WHERE c.timestamp<:end AND d.account_id=:account_id "
                       "ORDER BY ref_id) "
                       "LEFT JOIN accounts AS a ON a.id = :account_id "
                       "LEFT JOIN quotes AS q ON ref_id >= q.timestamp AND a.currency_id=q.asset_id "
                       "GROUP BY ref_id",
                       [(":begin", begin), (":end", end), (":account_id", account_id)])
        self.db.commit()

        header_row = {
            0: ("Ценная бумага", formats.ColumnHeader(), 8, 0, 0),
            1: ("Кол-во", formats.ColumnHeader(), 8, 0, 0),
            2: ("Тип сделки", formats.ColumnHeader(), 8, 0, 0),
            3: ("Дата сделки", formats.ColumnHeader(), 10, 0, 0),
            4: ("Курс USD/RUB на дату сделки", formats.ColumnHeader(), 9, 0, 0),
            5: ("Дата поставки", formats.ColumnHeader(), 10, 0, 0),
            6: ("Курс USD/RUB на дату поставки", formats.ColumnHeader(), 9, 0, 0),
            7: ("Цена, USD", formats.ColumnHeader(), 12, 0, 0),
            8: ("Сумма сделки, USD", formats.ColumnHeader(), 12, 0, 0),
            9: ("Сумма сделки, RUB", formats.ColumnHeader(), 12, 0, 0),
            10: ("Комиссия, USD", formats.ColumnHeader(), 12, 0, 0),
            11: ("Комиссия, RUB", formats.ColumnHeader(), 9, 0, 0),
            12: ("Доход, RUB", formats.ColumnHeader(), 12, 0, 0),
            13: ("Расход, RUB", formats.ColumnHeader(), 12, 0, 0),
            14: ("Финансовый результат, RUB", formats.ColumnHeader(), 12, 0, 0)
        }
        xlsxWriteRow(sheet, 7, header_row, 60)
        for column in range(len(header_row)):  # Put column numbers for reference
            header_row[column] = (f"({column + 1})", formats.ColumnHeader())
        xlsxWriteRow(sheet, 8, header_row)

        # Take all actions without conversion
        query = executeSQL(self.db,
                           "SELECT s.name AS symbol, d.qty AS qty, "
                           "o.timestamp AS o_date, qo.quote AS o_rate, o.settlement AS os_date, "
                           "qos.quote AS os_rate, o.price AS o_price, o.fee AS o_fee, "
                           "c.timestamp AS c_date, qc.quote AS c_rate, c.settlement AS cs_date, "
                           "qcs.quote AS cs_rate, c.price AS c_price, c.fee AS c_fee, "
                           "coalesce(ao.type, ac.type, 0) AS corp_action_type "
                           "FROM deals AS d "
                           "LEFT JOIN sequence AS os ON os.id=d.open_sid "
                           "LEFT JOIN trades AS o ON os.operation_id=o.id "
                           "LEFT JOIN sequence AS cs ON cs.id=d.close_sid "
                           "LEFT JOIN trades AS c ON cs.operation_id=c.id "
                           "LEFT JOIN assets AS s ON o.asset_id=s.id "
                           "LEFT JOIN accounts AS a ON a.id = :account_id "
                           "LEFT JOIN t_last_dates AS ldo ON o.timestamp=ldo.ref_id "
                           "LEFT JOIN quotes AS qo ON ldo.timestamp=qo.timestamp AND a.currency_id=qo.asset_id "
                           "LEFT JOIN t_last_dates AS ldos ON o.settlement=ldos.ref_id "
                           "LEFT JOIN quotes AS qos ON ldos.timestamp=qos.timestamp AND a.currency_id=qos.asset_id "
                           "LEFT JOIN t_last_dates AS ldc ON c.timestamp=ldc.ref_id "
                           "LEFT JOIN quotes AS qc ON ldc.timestamp=qc.timestamp AND a.currency_id=qc.asset_id "
                           "LEFT JOIN t_last_dates AS ldcs ON c.settlement=ldcs.ref_id "
                           "LEFT JOIN quotes AS qcs ON ldcs.timestamp=qcs.timestamp AND a.currency_id=qcs.asset_id "
                           "LEFT JOIN corp_actions AS ao ON ao.id=o.corp_action_id "
                           "LEFT JOIN corp_actions AS ac ON ac.id=c.corp_action_id "
                           "WHERE c.timestamp>=:begin AND c.timestamp<:end "
                           "AND d.account_id=:account_id AND corp_action_type != 1 "
                           "ORDER BY o.timestamp, c.timestamp",
                           [(":begin", begin), (":end", end), (":account_id", account_id)])
        start_row = 9
        data_row = 0
        income_sum = 0.0
        spending_sum = 0.0
        profit_sum = 0.0
        while query.next():
            symbol, qty, o_date, o_fee_rate, os_date, o_rate, o_price, o_fee_usd, \
                c_date, c_fee_rate, cs_date, c_rate, c_price, c_fee_usd, corp_action_type = readSQLrecord(query)
            row = start_row + (data_row * 2)
            o_amount_usd = round(o_price * qty, 2)
            o_amount_rub = round(o_amount_usd * o_rate, 2)
            c_amount_usd = round(c_price * qty, 2)
            c_amount_rub = round(c_amount_usd * c_rate, 2)
            o_fee_rub = round(o_fee_usd * o_fee_rate, 2)
            c_fee_rub = round(c_fee_usd * c_fee_rate, 2)
            income = c_amount_rub
            spending = o_amount_rub + o_fee_rub + c_fee_rub
            xlsxWriteRow(sheet, row, {
                0: (symbol, formats.Text(data_row), 0, 0, 1),
                1: (float(qty), formats.Number(data_row, 0, True), 0, 0, 1),
                2: ("Покупка", formats.Text(data_row)),
                3: (datetime.fromtimestamp(o_date).strftime('%d.%m.%Y'), formats.Text(data_row)),
                4: (o_fee_rate, formats.Number(data_row, 4)),
                5: (datetime.fromtimestamp(os_date).strftime('%d.%m.%Y'), formats.Text(data_row)),
                6: (o_rate, formats.Number(data_row, 4)),
                7: (o_price, formats.Number(data_row, 6)),
                8: (o_amount_usd, formats.Number(data_row, 2)),
                9: (o_amount_rub, formats.Number(data_row, 2)),
                10: (o_fee_usd, formats.Number(data_row, 6)),
                11: (o_fee_rub, formats.Number(data_row, 2)),
                12: (income, formats.Number(data_row, 2), 0, 0, 1),
                13: (spending, formats.Number(data_row, 2), 0, 0, 1),
                14: (income - spending, formats.Number(data_row, 2), 0, 0, 1)
            })
            xlsxWriteRow(sheet, row + 1, {
                2: ("Продажа", formats.Text(data_row)),
                3: (datetime.fromtimestamp(c_date).strftime('%d.%m.%Y'), formats.Text(data_row)),
                4: (c_fee_rate, formats.Number(data_row, 4)),
                5: (datetime.fromtimestamp(cs_date).strftime('%d.%m.%Y'), formats.Text(data_row)),
                6: (c_rate, formats.Number(data_row, 4)),
                7: (c_price, formats.Number(data_row, 6)),
                8: (c_amount_usd, formats.Number(data_row, 2)),
                9: (c_amount_rub, formats.Number(data_row, 2)),
                10: (c_fee_usd, formats.Number(data_row, 6)),
                11: (c_fee_rub, formats.Number(data_row, 2))
            })
            income_sum += income
            spending_sum += spending
            profit_sum += income - spending
            data_row = data_row + 1
        row = start_row + (data_row * 2)
        xlsxWriteRow(sheet, row, {
            11: ("ИТОГО", formats.ColumnFooter()),
            12: (income_sum, formats.ColumnFooter()),
            13: (spending_sum, formats.ColumnFooter()),
            14: (profit_sum, formats.ColumnFooter())
        })