Tags: live-strategy, debugging

Debugging live strategy#

In this notebook, we show how to debug live trading strategy instance using Python and Jupyter notebook.

  • Downloading the trades from the live instance

  • Reading data to State object

  • Inspecting State in Python

Download live data#

  • Each strategy Docker instances offers a webhook that allows access the data of this strategy, include State object that is the flat file state of the all the strategy current and past decision making

  • Note that State class and any children classes in the state tree may have changes between versions and decoding might need you to use a specific version of trade-executor

[1]:
from tradeexecutor.monkeypatch.dataclasses_json import patch_dataclasses_json
from tradeexecutor.state.state import State
import requests

# Currently needed because unpatched dataclasses_json package issues
patch_dataclasses_json()

# Public internet endpoint as exposed by the trade executor Docker
webbhook_url = "https://pancake-eth-usd-sma.tradingstrategy.ai"

state_api = f"{webbhook_url}/state"

resp = requests.get(state_api)

state_blob = resp.content

print(f"Downloaded {len(state_blob):,} bytes state data")

state = State.from_json(state_blob)

print(f"trade-executor was launched at: {state.created_at}, we have {len(list(state.portfolio.get_all_trades()))} trades")
Downloaded 6,467 bytes state data
---------------------------------------------------------------------------
JSONDecodeError                           Traceback (most recent call last)
Cell In[1], line 19
     15 state_blob = resp.content
     17 print(f"Downloaded {len(state_blob):,} bytes state data")
---> 19 state = State.from_json(state_blob)
     21 print(f"trade-executor was launched at: {state.created_at}, we have {len(list(state.portfolio.get_all_trades()))} trades")

File ~/.pyenv/versions/3.10.8/lib/python3.10/site-packages/dataclasses_json/api.py:58, in DataClassJsonMixin.from_json(cls, s, parse_float, parse_int, parse_constant, infer_missing, **kw)
     49 @classmethod
     50 def from_json(cls: Type[A],
     51               s: JsonData,
   (...)
     56               infer_missing=False,
     57               **kw) -> A:
---> 58     kvs = json.loads(s,
     59                      parse_float=parse_float,
     60                      parse_int=parse_int,
     61                      parse_constant=parse_constant,
     62                      **kw)
     63     return cls.from_dict(kvs, infer_missing=infer_missing)

File ~/.pyenv/versions/3.10.8/lib/python3.10/json/__init__.py:346, in loads(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
    341     s = s.decode(detect_encoding(s), 'surrogatepass')
    343 if (cls is None and object_hook is None and
    344         parse_int is None and parse_float is None and
    345         parse_constant is None and object_pairs_hook is None and not kw):
--> 346     return _default_decoder.decode(s)
    347 if cls is None:
    348     cls = JSONDecoder

File ~/.pyenv/versions/3.10.8/lib/python3.10/json/decoder.py:337, in JSONDecoder.decode(self, s, _w)
    332 def decode(self, s, _w=WHITESPACE.match):
    333     """Return the Python representation of ``s`` (a ``str`` instance
    334     containing a JSON document).
    335
    336     """
--> 337     obj, end = self.raw_decode(s, idx=_w(s, 0).end())
    338     end = _w(s, end).end()
    339     if end != len(s):

File ~/.pyenv/versions/3.10.8/lib/python3.10/json/decoder.py:355, in JSONDecoder.raw_decode(self, s, idx)
    353     obj, end = self.scan_once(s, idx)
    354 except StopIteration as err:
--> 355     raise JSONDecodeError("Expecting value", s, err.value) from None
    356 return obj, end

JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Examining data#

You can check what individual persistent objects are made of.

In this example, we have one blockchain trade whose transactions were broadcasted to the blockchain, but for which we never got transaction receipts back to the blockchain.

[ ]:
# Inspect a single position
position = next(iter(state.portfolio.closed_positions.values()))
print(position)

print("Value: ", position.get_value())
print("Quantity: ", position.get_quantity())
print("Successful trades:")
for t in position.get_successful_trades():
    print(f"     {t}")

print("Failed trades:")
for t in position.get_failed_trades():
    print(f"     {t}")

print("Any trades:")
for trade_id, t in position.trades.items():
    print(f"     {t}")