diff --git a/.flake8 b/.flake8
index ee9d7c0..ab8846e 100644
--- a/.flake8
+++ b/.flake8
@@ -35,6 +35,9 @@ ignore =
     D104, # Missing docstring in public package
     D105, # Missing docstring in magic method
     D107, # Missing docstring in __init__
+    DAR101, # Missing parameter(s) in Docstring
+    DAR201, # Missing "Returns" in Docstring
+
     E800, # commented out code
     N814, # camelcase imported as constant
     WPS115, # upper-case constant in a class
diff --git a/README.md b/README.md
index d4ff259..8899dda 100644
--- a/README.md
+++ b/README.md
@@ -16,11 +16,12 @@ $ pip install investments --upgrade --user
 - конвертация по курсу ЦБ
 - раздельный результат сделок по акциям и опционам + дивиденды
 - учёт начисленных процентов на остаток по счету
-- пока **НЕ** учитывает комисии по сделкам (т.е. налог будет немного больше, в пользу налоговой)
+- учитывает комисии по сделкам
 - пока **НЕ** поддерживаются сплиты
 - пока **НЕ** поддерживаются сделки Forex, сделка пропускается и выводится сообщение о том, что это может повлиять на итоговый отчет
 
 *Пример отчета:*
+TODO UPDATE example
 ![ibtax report example](./images/ibtax_2016.jpg)
 
 
diff --git a/investments/calculators.py b/investments/calculators.py
new file mode 100644
index 0000000..0259a0d
--- /dev/null
+++ b/investments/calculators.py
@@ -0,0 +1,16 @@
+"""Калькулятор цены сделки с учётом комиссий."""
+
+from investments.money import Money
+
+
+def compute_total_cost(quantity: int, price_per_piece: Money, fee_per_piece: Money) -> Money:
+    """Полная сумма сделки (цена +/- комиссии) в базовой валюте (Basis в отчёте)."""
+    assert price_per_piece.currency is fee_per_piece.currency
+    fee = abs(quantity) * abs(fee_per_piece)
+    price = abs(quantity) * price_per_piece
+    if quantity > 0:
+        # buy trade
+        return -1 * (price + fee)
+
+    # sell trade
+    return price - fee
diff --git a/investments/data_providers/cbr.py b/investments/data_providers/cbr.py
index 9037625..c31670f 100644
--- a/investments/data_providers/cbr.py
+++ b/investments/data_providers/cbr.py
@@ -42,6 +42,7 @@ def __init__(self, currency: Currency, year_from: int = 2000, cache_dir: str = N
 
         end_date = (datetime.datetime.utcnow() + datetime.timedelta(days=1)).strftime('%d/%m/%Y')
         r = requests.get(f'http://www.cbr.ru/scripts/XML_dynamic.asp?date_req1=01/01/{year_from}&date_req2={end_date}&VAL_NM_RQ={currency_code}')
+
         tree = ET.fromstring(r.text)
 
         rates_data: List[Tuple[datetime.date, Money]] = []
@@ -65,10 +66,18 @@ def __init__(self, currency: Currency, year_from: int = 2000, cache_dir: str = N
     def dataframe(self) -> pandas.DataFrame:
         return self._df
 
-    def get_rate(self, date: datetime.date) -> Money:
-        return self._df.loc[date].item()
+    def get_rate(self, dt: datetime.date) -> Money:
+        if isinstance(dt, datetime.datetime):
+            dt = datetime.datetime.combine(dt.date(), datetime.datetime.min.time())
+
+        if isinstance(dt, datetime.date):
+            dt = datetime.datetime.combine(dt, datetime.datetime.min.time())
+
+        return self._df.loc[dt].item()
 
     def convert_to_rub(self, source: Money, rate_date: datetime.date) -> Money:
+        assert isinstance(rate_date, datetime.date)
+
         if source.currency == Currency.RUB:
             return Money(source.amount, Currency.RUB)
 
diff --git a/investments/ibtax/ibtax.py b/investments/ibtax/ibtax.py
index 225d789..98d4959 100644
--- a/investments/ibtax/ibtax.py
+++ b/investments/ibtax/ibtax.py
@@ -5,6 +5,7 @@
 
 import pandas  # type: ignore
 
+from investments.calculators import compute_total_cost
 from investments.currency import Currency
 from investments.data_providers import cbr
 from investments.dividend import Dividend
@@ -12,28 +13,42 @@
 from investments.interests import Interest
 from investments.money import Money
 from investments.report_parsers.ib import InteractiveBrokersReportParser
-from investments.trades_fifo import PortfolioElement, TradesAnalyzer
+from investments.trades_fifo import TradesAnalyzer, FinishedTrade, PortfolioElement  # noqa: I001
 
 
-def prepare_trades_report(df: pandas.DataFrame, cbr_client_usd: cbr.ExchangeRatesRUB) -> pandas.DataFrame:
+def prepare_trades_report(finished_trades: List[FinishedTrade], cbr_client_usd: cbr.ExchangeRatesRUB, verbose: bool) -> pandas.DataFrame:
+    # todo unittest for
+    trade_date_column = 'trade_date'
     tax_date_column = 'settle_date'
 
-    df['date'] = df['datetime'].dt.normalize()
+    df = pandas.DataFrame(finished_trades, columns=finished_trades[0]._fields)  # noqa: WPS437
+
+    df[trade_date_column] = df[trade_date_column].dt.normalize()
     df[tax_date_column] = pandas.to_datetime(df[tax_date_column])
 
     tax_years = df.groupby('N')[tax_date_column].max().map(lambda x: x.year).rename('tax_year')
     df = df.join(tax_years, how='left', on='N')
 
-    df = df.join(cbr_client_usd.dataframe, how='left', on=tax_date_column)
-    df['total_rub'] = df.apply(lambda x: cbr_client_usd.convert_to_rub(x['total'], x[tax_date_column]).round(digits=2), axis=1)
+    df['price_rub'] = df.apply(lambda x: cbr_client_usd.convert_to_rub(x['price'], x[tax_date_column]).round(digits=2), axis=1)
+    df['fee_per_piece_rub'] = df.apply(lambda x: cbr_client_usd.convert_to_rub(x['fee_per_piece'], x[trade_date_column]).round(digits=2), axis=1)
+
+    df['fee_per_piece'] = df.apply(lambda x: x['fee_per_piece'].round(digits=2), axis=1)
+    df['fee'] = df.apply(lambda x: (x['fee_per_piece'] * abs(x['quantity'])).round(digits=2), axis=1)
 
+    df['total'] = df.apply(lambda x: compute_total_cost(x['quantity'], x['price'], x['fee_per_piece']).round(digits=2), axis=1)
+    df['total_rub'] = df.apply(lambda x: compute_total_cost(x['quantity'], x['price_rub'], x['fee_per_piece_rub']).round(digits=2), axis=1)
+
+    df = df.join(cbr_client_usd.dataframe['rate'].rename('settle_rate'), how='left', on=tax_date_column)
+    df = df.join(cbr_client_usd.dataframe['rate'].rename('fee_rate'), how='left', on=trade_date_column)
     df['profit_rub'] = df['total_rub']
-    df.loc[df['quantity'] >= 0, 'profit_rub'] *= -1
 
     profit = df.groupby('N')['profit_rub'].sum().reset_index().set_index('N')
     df = df.join(profit, how='left', on='N', lsuffix='del')
     df.drop(columns=['profit_rubdel'], axis=0, inplace=True)
-    df.loc[~df.index.isin(df.groupby('N')['datetime'].idxmax()), 'profit_rub'] = Money(0, Currency.RUB)
+    df.loc[~df.index.isin(df.groupby('N')[trade_date_column].idxmax()), 'profit_rub'] = Money(0, Currency.RUB)
+
+    if not verbose:
+        df = df.drop(columns=['fee_per_piece', 'fee_per_piece_rub', 'price_rub'])
 
     return df
 
@@ -65,8 +80,7 @@ def prepare_fees_report(fees: List[Fee], cbr_client_usd: cbr.ExchangeRatesRUB) -
         (i + 1, pandas.to_datetime(x.date), x.amount, x.description, x.date.year)
         for i, x in enumerate(fees)
     ]
-    df = pandas.DataFrame(df_data, columns=['N', 'date', 'amount', 'description', 'tax_year'])
-
+    df = pandas.DataFrame(df_data, columns=['N', operation_date_column, 'amount', 'description', 'tax_year'])
     df = df.join(cbr_client_usd.dataframe, how='left', on=operation_date_column)
 
     df['amount_rub'] = df.apply(lambda x: cbr_client_usd.convert_to_rub(x['amount'], x[operation_date_column]).round(digits=2), axis=1)
@@ -79,10 +93,8 @@ def prepare_interests_report(interests: List[Interest], cbr_client_usd: cbr.Exch
         (i + 1, pandas.to_datetime(x.date), x.amount, x.description, x.date.year)
         for i, x in enumerate(interests)
     ]
-    df = pandas.DataFrame(df_data, columns=['N', 'date', 'amount', 'description', 'tax_year'])
-
+    df = pandas.DataFrame(df_data, columns=['N', operation_date_column, 'amount', 'description', 'tax_year'])
     df = df.join(cbr_client_usd.dataframe, how='left', on=operation_date_column)
-
     df['amount_rub'] = df.apply(lambda x: cbr_client_usd.convert_to_rub(x['amount'], x[operation_date_column]).round(digits=2), axis=1)
     return df
 
@@ -138,11 +150,11 @@ def show_report(trades: Optional[pandas.DataFrame], dividends: Optional[pandas.D
             _show_dividends_report(dividends, year)
 
         if trades is not None:
-            trades_year = trades[trades['tax_year'] == year].drop(columns=['tax_year', 'datetime'])
+            trades_year = trades[trades['tax_year'] == year].drop(columns=['tax_year'])
             trades_year['N'] -= trades_year['N'].iloc[0] - 1
 
             _show_header('TRADES')
-            print(trades_year.set_index(['N', 'ticker', 'date']).to_string())
+            print(trades_year.set_index(['N', 'ticker', 'trade_date']).to_string())
             print('\n\n')
 
             _show_header('TRADES RESULTS BEFORE TAXES')
@@ -153,7 +165,7 @@ def show_report(trades: Optional[pandas.DataFrame], dividends: Optional[pandas.D
             tp = tp['index'].apply(pandas.Series).join(tp).pivot(index=0, columns=1, values='total_rub')
             tp.index.name = ''
             tp.columns.name = ''
-            tp['profit'] = tp['income'] - tp['expenses']
+            tp['profit'] = tp['income'] + tp['expenses']
             print(tp.reset_index().to_string())
             print('\n\n')
 
@@ -226,7 +238,7 @@ def main():
         return
 
     # fixme first_year without dividends
-    first_year = min(trades[0].datetime.year, dividends[0].date.year) if dividends else trades[0].datetime.year
+    first_year = min(trades[0].trade_date.year, dividends[0].date.year) if dividends else trades[0].trade_date.year
     cbr_client_usd = cbr.ExchangeRatesRUB(currency=Currency.USD, year_from=first_year, cache_dir=args.cache_dir)
 
     dividends_report = prepare_dividends_report(dividends, cbr_client_usd, args.verbose) if dividends else None
@@ -237,11 +249,7 @@ def main():
     finished_trades = analyzer.finished_trades
     portfolio = analyzer.final_portfolio
 
-    if finished_trades:
-        finished_trades_df = pandas.DataFrame(finished_trades, columns=finished_trades[0]._fields)  # noqa: WPS437
-        trades_report = prepare_trades_report(finished_trades_df, cbr_client_usd)
-    else:
-        trades_report = None
+    trades_report = prepare_trades_report(finished_trades, cbr_client_usd, args.verbose) if finished_trades else None
 
     show_report(trades_report, dividends_report, fees_report, interests_report, args.years)
     show_portfolio_report(portfolio)
diff --git a/investments/money.py b/investments/money.py
index 93a5447..4403c54 100644
--- a/investments/money.py
+++ b/investments/money.py
@@ -48,6 +48,9 @@ def __add__(self, other) -> 'Money':
             raise TypeError(f'different currencies: {self._currency} & {other.currency}')
         return Money(self._amount + other.amount, self._currency)
 
+    def __abs__(self) -> 'Money':
+        return Money(abs(self.amount), self.currency)
+
     def __radd__(self, other) -> 'Money':
         return self.__add__(other)
 
diff --git a/investments/report_parsers/ib.py b/investments/report_parsers/ib.py
index dcc16a9..f8aac83 100644
--- a/investments/report_parsers/ib.py
+++ b/investments/report_parsers/ib.py
@@ -110,11 +110,11 @@ def __repr__(self):
         return f'IbParser(trades={len(self.trades)}, dividends={len(self.dividends)}, fees={len(self.fees)}, interests={len(self.interests)})'  # noqa: WPS221
 
     @property
-    def trades(self) -> List:
+    def trades(self) -> List[Trade]:
         return self._trades
 
     @property
-    def dividends(self) -> List:
+    def dividends(self) -> List[Dividend]:
         return self._dividends
 
     @property
@@ -161,7 +161,7 @@ def parse_csv(self, *, activity_csvs: List[str], trade_confirmation_csvs: List[s
                 })
 
         # 4. sort
-        self._trades.sort(key=lambda x: x.datetime)
+        self._trades.sort(key=lambda x: x.trade_date)
         self._dividends.sort(key=lambda x: x.date)
         self._interests.sort(key=lambda x: x.date)
         self._deposits_and_withdrawals.sort(key=lambda x: x[0])
@@ -231,7 +231,7 @@ def _parse_trades(self, f: Dict[str, str]):
 
         self._trades.append(Trade(
             ticker=ticker,
-            datetime=dt,
+            trade_date=dt,
             settle_date=settle_date,
             quantity=int(f['Quantity']) * quantity_multiplier,
             price=Money(f['T. Price'], currency),
diff --git a/investments/report_parsers/open_fr.py b/investments/report_parsers/open_fr.py
index 2bc2375..c5b9472 100644
--- a/investments/report_parsers/open_fr.py
+++ b/investments/report_parsers/open_fr.py
@@ -98,7 +98,7 @@ def parse_xml(self, xml_file_name: str):
         self._parse_non_trade_operations(tree)
         self._parse_trades(tree)
 
-        self._trades.sort(key=lambda x: x.datetime)
+        self._trades.sort(key=lambda x: x.trade_date)
         self._dividends.sort(key=lambda x: x.date)
         self._deposits_and_withdrawals.sort(key=lambda x: x[0])
 
@@ -121,7 +121,7 @@ def _parse_cb_convertation(self, f):
         dt = _parse_datetime(f['operation_date'])
         self._trades.append(Trade(
             ticker=ticker,
-            datetime=dt,
+            trade_date=dt,
             settle_date=dt,
             quantity=qnty,
             price=Money(0, Currency.RUB),  # TODO: other currencies
@@ -155,7 +155,7 @@ def _parse_money_payment(self, f, bonds_redemption):
             isin, quantity_buyout = m.group('isin'), int(m.group('quantity'))
             self._trades.append(Trade(
                 ticker=self._tickers.get(isin=isin),
-                datetime=dt,
+                trade_date=dt,
                 settle_date=dt,
                 quantity=-1 * quantity_buyout,
                 price=money_total / quantity_buyout,
@@ -171,7 +171,7 @@ def _parse_money_payment(self, f, bonds_redemption):
                 for (price, quantity_coupons) in ((Money(0, currency), 1), (money_total, -1)):
                     self._trades.append(Trade(
                         ticker=ticker,
-                        datetime=dt,
+                        trade_date=dt,
                         settle_date=dt,
                         quantity=quantity_coupons,
                         price=price,
@@ -184,7 +184,7 @@ def _parse_money_payment(self, f, bonds_redemption):
                 quantity_redemption = bonds_redemption[key]
                 self._trades.append(Trade(
                     ticker=ticker,
-                    datetime=dt,
+                    trade_date=dt,
                     settle_date=dt,
                     quantity=quantity_redemption,
                     price=-1 * money_total / int(quantity_redemption),
@@ -275,7 +275,7 @@ def _parse_trades(self, xml_tree: ET.ElementTree):
 
             self._trades.append(Trade(
                 ticker=ticker,
-                datetime=_parse_datetime(f['conclusion_time']),
+                trade_date=_parse_datetime(f['conclusion_time']),
                 settle_date=_parse_datetime(f['execution_date']),
                 quantity=int(qnty),
                 price=price,
diff --git a/investments/trade.py b/investments/trade.py
index ebfdc3d..945031e 100644
--- a/investments/trade.py
+++ b/investments/trade.py
@@ -7,8 +7,21 @@
 
 class Trade(NamedTuple):
     ticker: Ticker
-    datetime: datetime.datetime
+    trade_date: datetime.datetime
     settle_date: datetime.date
     quantity: int
+
+    # цена одной бумаги
     price: Money
+
+    # комиссия за сделку
     fee: Money
+
+    @property
+    def settle_datetime(self) -> datetime.datetime:
+        return datetime.datetime.combine(self.settle_date, datetime.datetime.min.time())
+
+    @property
+    def fee_per_piece(self) -> Money:
+        """Комиссия за сделку за одну бумагу, полезно для расчёта налогов."""
+        return self.fee / abs(self.quantity)
diff --git a/investments/trades_fifo.py b/investments/trades_fifo.py
index d1c0558..e574997 100644
--- a/investments/trades_fifo.py
+++ b/investments/trades_fifo.py
@@ -2,6 +2,7 @@
 from collections import defaultdict
 from typing import Any, Dict, Iterable, List, NamedTuple, Optional, Tuple
 
+from investments.calculators import compute_total_cost
 from investments.money import Money
 from investments.ticker import Ticker
 from investments.trade import Trade
@@ -10,12 +11,21 @@
 class FinishedTrade(NamedTuple):
     N: int
     ticker: Ticker
-    datetime: datetime.datetime
+
+    # дата сделки, нужна для расчёта комиссии в рублях на дату
+    trade_date: datetime.datetime
+
+    # дата поставки, нужна для расчёта цены сделки в рублях на дату
     settle_date: datetime.date
+
+    # количество бумаг, "+/-"
     quantity: int
+
+    # цена одной бумаги, "+"
     price: Money
-    total: Money
-    profit: Money
+
+    # комиссия за сделку с одной бумагой, "-"
+    fee_per_piece: Money
 
 
 class PortfolioElement(NamedTuple):
@@ -49,36 +59,34 @@ def analyze_trades(self, trades: Iterable[Trade]):
                     break
                 assert q != 0
 
-                self._finished_trades.append(FinishedTrade(
-                    finished_trade_id,
-                    trade.ticker,
-                    matched_trade.datetime,
-                    matched_trade.settle_date,
-                    q,
-                    matched_trade.price,
-                    abs(q) * matched_trade.price,
-                    Money(0, trade.price.currency),
-                ))
+                total_cost = compute_total_cost(q, matched_trade.price, matched_trade.fee_per_piece)
+
+                finished_trade = FinishedTrade(
+                    finished_trade_id, trade.ticker, matched_trade.trade_date, matched_trade.settle_date, q,
+                    matched_trade.price, matched_trade.fee_per_piece,
+                )
+                self._finished_trades.append(finished_trade)
+
+                q = -1 * q
 
-                profit = q * (trade.price - matched_trade.price)
+                profit = compute_total_cost(q, trade.price, trade.fee_per_piece) + total_cost
                 if total_profit is None:
                     total_profit = profit
                 else:
                     total_profit += profit
 
-                quantity -= -1 * q
+                quantity -= q
 
             if total_profit is not None:
                 q = trade.quantity - quantity
                 self._finished_trades.append(FinishedTrade(
                     finished_trade_id,
                     trade.ticker,
-                    trade.datetime,
+                    trade.trade_date,
                     trade.settle_date,
                     q,
                     trade.price,
-                    abs(q) * trade.price,
-                    total_profit,
+                    trade.fee_per_piece,
                 ))
                 finished_trade_id += 1
 
@@ -96,15 +104,15 @@ def final_portfolio(self) -> List[PortfolioElement]:
         return self._portfolio
 
 
-def sign(v: int) -> int:
-    assert v != 0
-    return -1 if v < 0 else 1
-
-
 class _TradesFIFO:
     def __init__(self):
         self._portfolio = defaultdict(list)
 
+    @staticmethod
+    def sign(v: int) -> int:
+        assert v != 0
+        return -1 if v < 0 else 1
+
     def put(self, quantity: int, trade: Trade):
         """
         Put trade to the storage.
@@ -113,10 +121,10 @@ def put(self, quantity: int, trade: Trade):
             quantity (int): The real quantity of the trade, >0 for BUY trades & <0 for SELL trades
             trade (Trade): Base trade, quantity field not used
         """
-        assert sign(quantity) == sign(trade.quantity)
+        assert self.sign(quantity) == self.sign(trade.quantity)
         assert abs(quantity) <= abs(trade.quantity)
         if self._portfolio[trade.ticker]:
-            assert sign(quantity) == sign(self._portfolio[trade.ticker][0]['quantity'])
+            assert self.sign(quantity) == self.sign(self._portfolio[trade.ticker][0]['quantity'])
 
         self._portfolio[trade.ticker].append({
             'trade': trade,
@@ -139,10 +147,10 @@ def match(self, quantity: int, ticker: Ticker) -> Tuple[Optional[Trade], int]:
             return None, 0
 
         front = self._portfolio[ticker][0]
-        fqsign = sign(front['quantity'])
+        fqsign = self.sign(front['quantity'])
 
         # only match BUY with SELL and vice versa
-        if sign(quantity) == fqsign:
+        if self.sign(quantity) == fqsign:
             return None, 0
 
         q = fqsign * min(abs(quantity), abs(front['quantity']))
diff --git a/tests/calculators_test.py b/tests/calculators_test.py
new file mode 100644
index 0000000..8e8ad2e
--- /dev/null
+++ b/tests/calculators_test.py
@@ -0,0 +1,13 @@
+from investments.currency import Currency
+from investments.calculators import compute_total_cost
+from investments.money import Money
+
+
+def test_compute_total_cost():
+    buy_cost = compute_total_cost(10, Money(1.7, Currency.USD), Money(-0.1, Currency.USD))
+    assert buy_cost.amount == -1 * ((10 * 1.7) + (10 * 0.1))
+    assert buy_cost.currency is Currency.USD
+
+    sell_cost = compute_total_cost(-10, Money(1.7, Currency.USD), Money(-0.1, Currency.USD))
+    assert sell_cost.amount == (10 * 1.7) - (10 * 0.1)
+    assert sell_cost.currency is Currency.USD
diff --git a/tests/data_providers/cbr_test.py b/tests/data_providers/cbr_test.py
index 7848b3d..a1ca352 100644
--- a/tests/data_providers/cbr_test.py
+++ b/tests/data_providers/cbr_test.py
@@ -1,4 +1,4 @@
-from datetime import datetime
+from datetime import datetime, date
 from decimal import Decimal
 
 import pytest  # type: ignore
@@ -8,13 +8,13 @@
 from investments.data_providers.cbr import ExchangeRatesRUB
 from investments.money import Money
 
-
 test_cases = [
     (datetime(2015, 1, 15), Currency.USD, Money('66.0983', Currency.RUB)),
     (datetime(2015, 3, 7), Currency.USD, Money('59.9938', Currency.RUB)),
     (datetime(2015, 3, 8), Currency.USD, Money('59.9938', Currency.RUB)),
     (datetime(2020, 3, 31), Currency.USD, Money('77.7325', Currency.RUB)),
     (datetime(2020, 1, 9), Currency.USD, Money('61.9057', Currency.RUB)),
+    (date(2020, 2, 4), Currency.EUR, Money('70.7921', Currency.RUB)),
 
     (datetime(2015, 3, 7), Currency.EUR, Money('66.1012', Currency.RUB)),
     (datetime(2015, 1, 15), Currency.EUR, Money('77.9629', Currency.RUB)),
diff --git a/tests/money_test.py b/tests/money_test.py
index 9477bd6..37c8884 100644
--- a/tests/money_test.py
+++ b/tests/money_test.py
@@ -1,3 +1,5 @@
+from decimal import Decimal
+
 import pytest
 
 from investments.currency import Currency
@@ -41,6 +43,10 @@ def test_money():
     assert r.amount == 2
     assert r.currency == Currency.RUB
 
+    negative_money = Money(-1, Currency.RUB)
+    assert negative_money.amount == Decimal('-1')
+    assert abs(negative_money).amount == Decimal('1')
+
 
 def test_money_zero():
     rub3 = Money(3, Currency.RUB)
diff --git a/tests/report_parsers/ib_test.py b/tests/report_parsers/ib_test.py
index a0a8114..e396441 100644
--- a/tests/report_parsers/ib_test.py
+++ b/tests/report_parsers/ib_test.py
@@ -167,20 +167,24 @@ def test_parse_trades_with_fees():
 
     # buy trade
     assert p.trades[0].ticker.symbol == 'VT'
-    assert p.trades[0].datetime == _parse_datetime('2020-01-31, 09:30:00')
+    assert p.trades[0].trade_date == _parse_datetime('2020-01-31, 09:30:00')
     assert p.trades[0].settle_date == _parse_date('2020-02-04')
     assert p.trades[0].quantity == 10
     assert p.trades[0].price.amount == Decimal('80.62')
     assert p.trades[0].price.currency == Currency.USD
     assert p.trades[0].fee.amount == Decimal('-1')
     assert p.trades[0].fee.currency == Currency.USD
+    assert p.trades[0].fee_per_piece.currency == Currency.USD
+    assert p.trades[0].fee_per_piece.amount == Decimal('-0.1')
 
     # sell trade
     assert p.trades[1].ticker.symbol == 'VT'
-    assert p.trades[1].datetime == _parse_datetime('2020-02-10, 09:38:00')
+    assert p.trades[1].trade_date == _parse_datetime('2020-02-10, 09:38:00')
     assert p.trades[1].settle_date == _parse_date('2020-02-12')
     assert p.trades[1].quantity == -10
     assert p.trades[1].price.amount == Decimal('81.82')
     assert p.trades[1].price.currency == Currency.USD
     assert p.trades[1].fee.amount == Decimal('-1.01812674')
     assert p.trades[1].fee.currency == Currency.USD
+    assert p.trades[1].fee_per_piece.amount == Decimal('-0.101812674')
+    assert p.trades[1].fee_per_piece.currency == Currency.USD
diff --git a/tests/trades_fifo_test.py b/tests/trades_fifo_test.py
index e3f4a78..372c290 100644
--- a/tests/trades_fifo_test.py
+++ b/tests/trades_fifo_test.py
@@ -1,4 +1,5 @@
 import datetime
+from decimal import Decimal
 
 import pytest
 
@@ -6,47 +7,43 @@
 from investments.money import Money
 from investments.ticker import Ticker, TickerKind
 from investments.trade import Trade
-from investments.trades_fifo import TradesAnalyzer
+from investments.trades_fifo import TradesAnalyzer, FinishedTrade
 
 analyze_trades_fifo_testdata = [
     # trades: [(Date, Symbol, Quantity, Price)]
-    # expect_trades: (N, Symbol, Quantity, Total, Profit)
-
-    # basic case with custom fees
-    ([('2018-01-01', 'TEST', 100, 4.2), ('2018-01-04', 'TEST', 50, 17.5), ('2018-01-07', 'TEST', -100, 50.3)],
-     [(1, 'TEST', 100, 420, 0), (1, 'TEST', -100, 5030, 4610)]),
+    # expect_trades: (N, Symbol, Quantity)
 
     # basic cases
     ([('2018-01-01', 'TEST', 100, 4.2), ('2018-01-04', 'TEST', 50, 17.5), ('2018-01-07', 'TEST', -100, 50.3)],
-     [(1, 'TEST', 100, 420, 0), (1, 'TEST', -100, 5030, 4610)]),
+     [(1, 'TEST', 100), (1, 'TEST', -100)]),
 
     ([('2018-01-01', 'TEST', 100, 4.2), ('2018-01-04', 'TEST', 50, 17.5), ('2018-01-07', 'TEST', -130, 50.3)],
-     [(1, 'TEST', 100, 420, 0), (1, 'TEST', 30, 525, 0), (1, 'TEST', -130, 6539, 5594)]),
+     [(1, 'TEST', 100), (1, 'TEST', 30), (1, 'TEST', -130)]),
 
     ([('2018-01-01', 'TEST', -100, 4.2), ('2018-01-04', 'TEST', 30, 17.5)],
-     [(1, 'TEST', -30, 126, 0), (1, 'TEST', 30, 525, -399)]),
+     [(1, 'TEST', -30), (1, 'TEST', 30)]),
 
     # issue #8 - sell all & open short in one trade
     ([('2018-01-01', 'TEST', 10, 4.2), ('2018-01-04', 'TEST', -10, 17.5), ('2018-01-05', 'TEST', -3, 17.5)],
-     [(1, 'TEST', 10, 42, 0), (1, 'TEST', -10, 175, 133)]),
+     [(1, 'TEST', 10), (1, 'TEST', -10)]),
 
     ([('2018-01-01', 'TEST', 10, 4.2), ('2018-01-05', 'TEST', -13, 17.5)],
-     [(1, 'TEST', 10, 42, 0), (1, 'TEST', -10, 175, 133)]),
+     [(1, 'TEST', 10), (1, 'TEST', -10)]),
 ]
 
 
 @pytest.mark.parametrize("trades,expect_trades", analyze_trades_fifo_testdata)
-def test_analyze_trades_fifo(trades, expect_trades):
+def test_analyze_trades_without_fees(trades, expect_trades):
     request_trades = []
     for date, ticker, qty, price in trades:
         dt = datetime.datetime.strptime(date, '%Y-%m-%d')
         request_trades.append(Trade(
             ticker=Ticker(symbol=ticker, kind=TickerKind.Stock),
-            datetime=dt,
+            trade_date=dt,
             settle_date=dt.date(),
             quantity=qty,
             price=Money(price, Currency.USD),
-            fee=Money(-1, Currency.USD),
+            fee=Money(0, Currency.USD),
         ))
 
     finished_trades = TradesAnalyzer(request_trades).finished_trades
@@ -57,5 +54,45 @@ def test_analyze_trades_fifo(trades, expect_trades):
         assert expected[0] == trade.N, f'expect trade N={expected[0]} but got {trade.N}'
         assert expected[1] == trade.ticker.symbol, f'expect trade ticker={expected[1]} but got {trade.ticker.symbol}'
         assert expected[2] == trade.quantity, f'expect trade quantity={expected[2]} but got {trade.quantity}'
-        assert expected[3] == trade.total.amount, f'expect trade total={expected[3]} but got {trade.total.amount}'
-        assert expected[4] == trade.profit.amount, f'expect trade profit={expected[4]} but got {trade.profit.amount}'
+
+
+def test_trades_fees_simple():
+    request_trades = []
+    ticker = Ticker(symbol='VT', kind=TickerKind.Stock)
+
+    # buy 10
+    request_trades.append(Trade(
+        ticker=ticker,
+        trade_date=datetime.datetime(year=2020, month=1, day=31),  # 63,0359₽
+        settle_date=datetime.datetime(year=2020, month=2, day=4),  # 63,9091₽
+        quantity=10,
+        price=Money(80.62, Currency.USD),
+        fee=Money(-1, Currency.USD),
+    ))
+    # sell 10
+    request_trades.append(Trade(
+        ticker=ticker,
+        trade_date=datetime.datetime(year=2020, month=2, day=10),  # 63,4720₽
+        settle_date=datetime.datetime(year=2020, month=2, day=12),  # 63,9490₽
+        quantity=-10,
+        price=Money(81.82, Currency.USD),
+        fee=Money(Decimal('-1.01812674'), Currency.USD),
+    ))
+
+    finished_trades = TradesAnalyzer(request_trades).finished_trades
+
+    assert len(finished_trades) == 2
+
+    buy_trade: FinishedTrade = finished_trades[0]
+    assert buy_trade.trade_date == datetime.datetime(year=2020, month=1, day=31)
+    assert buy_trade.settle_date == datetime.datetime(year=2020, month=2, day=4)
+    assert buy_trade.quantity == 10
+    assert buy_trade.price.amount == Decimal('80.62')
+    assert buy_trade.fee_per_piece.amount == Decimal('-0.1')
+
+    sell_trade: FinishedTrade = finished_trades[1]
+    assert sell_trade.trade_date == datetime.datetime(year=2020, month=2, day=10)
+    assert sell_trade.settle_date == datetime.datetime(year=2020, month=2, day=12)
+    assert sell_trade.quantity == -10
+    assert sell_trade.price.amount == Decimal('81.82')
+    assert sell_trade.fee_per_piece.amount == Decimal('-0.101812674')
diff --git a/tests/trades_portfolio_test.py b/tests/trades_portfolio_test.py
index 042f994..bb01bf6 100644
--- a/tests/trades_portfolio_test.py
+++ b/tests/trades_portfolio_test.py
@@ -15,11 +15,11 @@ def test_analyze_portfolio_different_kinds():
     dt = datetime.datetime.now()
 
     request_trades = [
-        Trade(ticker=ticker_stock, datetime=dt, settle_date=dt.date(), quantity=-3, price=Money(4.2, Currency.USD),
+        Trade(ticker=ticker_stock, trade_date=dt, settle_date=dt.date(), quantity=-3, price=Money(4.2, Currency.USD),
               fee=Money(1, Currency.USD)),
-        Trade(ticker=ticker_stock, datetime=dt, settle_date=dt.date(), quantity=8, price=Money(4.2, Currency.USD),
+        Trade(ticker=ticker_stock, trade_date=dt, settle_date=dt.date(), quantity=8, price=Money(4.2, Currency.USD),
               fee=Money(1, Currency.USD)),
-        Trade(ticker=ticker_option, datetime=dt, settle_date=dt.date(), quantity=10, price=Money(4.2, Currency.USD),
+        Trade(ticker=ticker_option, trade_date=dt, settle_date=dt.date(), quantity=10, price=Money(4.2, Currency.USD),
               fee=Money(1, Currency.USD)),
     ]
 
@@ -53,7 +53,7 @@ def test_analyze_portfolio(trades: list, expect_portfolio: dict):
         dt = datetime.datetime.strptime(date, '%Y-%m-%d')
         request_trades.append(Trade(
             ticker=Ticker(symbol=ticker, kind=TickerKind.Stock),
-            datetime=dt,
+            trade_date=dt,
             settle_date=dt.date(),
             quantity=qty,
             price=Money(1, Currency.USD),