Repository: rotki/rotki

Issue:
Ledger actions from before the requested PnL report period are not counted
## Problem Definition

If a user tries to create a PnL report of a certain time period, and that period contains assets whose cost basis was calculated thanks to Ledger Actions from before the time period then this cost basis is not seen.

The reason for this is .... :drum: this line: https://github.com/rotki/rotki/blob/4fd6c0d734d38223f6cc4cf5e0d145da263e3208/rotkehlchen/history/events.py#L131

`start_ts` should be 0, so that all ledger actions are processed, not just the ones inside the query period. Essentially same behavior with all other history event types.

## Task

- [ ] Fix it
- [ ] Write a test for it. A simple one suffices. Add 2 history events. A ledger action giving you 100 ETH at time `X`. A sell of ETH for EUR at time `X + 5`. Do a PnL report from time `X+3` and see that the cost basis is calculated correctly.


Discussion:
I'm a bit confused with the test here. Since I need to add the assets movements I'll need to work with the `accountant` (I haven't seen how to do this using `rotkehlchen_api_server`). But to generate the PnL in the range I believe I need to call the `rotkehlchen_api_server` and ask for the history... Is there another way to do this? Using both fixtures creates an error with duplicate accounts
You are right to be confused. I did not specify the test nicely in the issue.

I think a unit test of the corresponding function here would be sufficient:

https://github.com/rotki/rotki/blob/8833d0f327a3039cf338d20af03951738f4a0d49/rotkehlchen/history/events.py#L116-L136

Just make sure that it returns ledger actions before the from_ts.

I don't think this is possible to be tested in any other way since we don't test the `EventHistorian::get_history()` anywhere else. The accounting tests take specific history.

Resolving patch:
diff --git a/rotkehlchen/history/events.py b/rotkehlchen/history/events.py
--- a/rotkehlchen/history/events.py
+++ b/rotkehlchen/history/events.py
@@ -227,7 +227,7 @@ def fail_history_cb(error_msg: str) -> None:
 
         # include the ledger actions
         self.processing_state_name = 'Querying ledger actions history'
-        ledger_actions, _ = self.query_ledger_actions(has_premium, from_ts=start_ts, to_ts=end_ts)
+        ledger_actions, _ = self.query_ledger_actions(has_premium, from_ts=None, to_ts=end_ts)
         step = self._increase_progress(step, total_steps)
 
         # include AMM trades: balancer, uniswap


Test patch:
diff --git a/rotkehlchen/tests/fixtures/history.py b/rotkehlchen/tests/fixtures/history.py
--- a/rotkehlchen/tests/fixtures/history.py
+++ b/rotkehlchen/tests/fixtures/history.py
@@ -1,6 +1,5 @@
 import pytest
 
-from rotkehlchen.db.dbhandler import DBHandler
 from rotkehlchen.exchanges.manager import ExchangeManager
 from rotkehlchen.externalapis.coingecko import Coingecko
 from rotkehlchen.externalapis.cryptocompare import Cryptocompare
@@ -60,13 +59,7 @@ def price_historian(
 
 
 @pytest.fixture
-def events_historian(data_dir, function_scope_messages_aggregator, blockchain):
-    database = DBHandler(
-        user_data_dir=data_dir,
-        password='123',
-        msg_aggregator=function_scope_messages_aggregator,
-        initial_settings=None,
-    )
+def events_historian(database, data_dir, function_scope_messages_aggregator, blockchain):
     exchange_manager = ExchangeManager(msg_aggregator=function_scope_messages_aggregator)
     historian = EventsHistorian(
         user_directory=data_dir,
diff --git a/rotkehlchen/tests/unit/test_history.py b/rotkehlchen/tests/unit/test_history.py
--- a/rotkehlchen/tests/unit/test_history.py
+++ b/rotkehlchen/tests/unit/test_history.py
@@ -1,8 +1,10 @@
-from rotkehlchen.constants.assets import A_ETH
+from rotkehlchen.accounting.structures import LedgerActionType
+from rotkehlchen.db.ledger_actions import DBLedgerActions
+from rotkehlchen.constants.assets import A_ETH, A_USDC
 from rotkehlchen.exchanges.data_structures import Trade
 from rotkehlchen.fval import FVal
 from rotkehlchen.history.events import limit_trade_list_to_period
-from rotkehlchen.typing import Location, TradeType
+from rotkehlchen.typing import Location, TradeType, Timestamp
 
 
 def test_limit_trade_list_to_period():
@@ -57,3 +59,54 @@ def test_limit_trade_list_to_period():
     assert limit_trade_list_to_period(full_list, 1459427707, 1459427707) == [trade1]
     assert limit_trade_list_to_period(full_list, 1469427707, 1469427707) == [trade2]
     assert limit_trade_list_to_period(full_list, 1479427707, 1479427707) == [trade3]
+
+
+def test_query_ledger_actions(events_historian, function_scope_messages_aggregator):
+    """
+    Create actions and query the events historian to check that the history
+    has events previous to the selected from_ts. This allows us to verify that
+    actions before one period are counted in the PnL report to calculate cost basis.
+    https://github.com/rotki/rotki/issues/2541
+    """
+
+    selected_timestamp = 10
+    db = DBLedgerActions(events_historian.db, function_scope_messages_aggregator)
+
+    db.add_ledger_action(
+        timestamp=selected_timestamp - 2,
+        action_type=LedgerActionType.INCOME,
+        location=Location.EXTERNAL,
+        amount=FVal(1),
+        asset=A_ETH,
+        link='',
+        notes='',
+    )
+
+    db.add_ledger_action(
+        timestamp=selected_timestamp + 3,
+        action_type=LedgerActionType.EXPENSE,
+        location=Location.EXTERNAL,
+        amount=FVal(0.5),
+        asset=A_ETH,
+        link='',
+        notes='',
+    )
+
+    db.add_ledger_action(
+        timestamp=selected_timestamp + 5,
+        action_type=LedgerActionType.INCOME,
+        location=Location.EXTERNAL,
+        amount=FVal(10),
+        asset=A_USDC,
+        link='',
+        notes='',
+    )
+
+    actions, length = events_historian.query_ledger_actions(
+        has_premium=True,
+        from_ts=None,
+        to_ts=Timestamp(selected_timestamp + 4),
+    )
+
+    assert any((action.timestamp < selected_timestamp for action in actions))
+    assert length == 2