Skip to content

Commit

Permalink
Trader livemocking. (#568)
Browse files Browse the repository at this point in the history
* Trader livemocking.
* Add test and validation of tradetype input.
* Move MockExchange separately.
  • Loading branch information
calina-c authored Jan 24, 2024
1 parent 4af7175 commit e3ceba9
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 6 deletions.
6 changes: 3 additions & 3 deletions READMEs/trader.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ Update `my_ppss.yaml` as desired.

Then, run a simple trading bot. In console:
```console
pdr trader 2 my_ppss.yaml sapphire-testnet
pdr trader 2 my_ppss.yaml sapphire-testnet
```

Your bot is running, congrats! Sit back and watch it in action.
Your bot is running, congrats! Sit back and watch it in action.

You can track behavior at finer resolution by writing more logs to the [code](../pdr_backend/trader/trader_agent.py), or [querying Predictoor subgraph](subgraph.md).

Expand All @@ -105,7 +105,7 @@ Update `my_ppss.yaml` as desired.

Then, run the bot. In console:
```console
pdr trader 2 my_ppss.yaml sapphire-mainnet
pdr trader 2 my_ppss.yaml sapphire-mainnet
```

This is where there's real $ at stake. Good luck!
Expand Down
21 changes: 19 additions & 2 deletions pdr_backend/ppss/base_ss.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import copy
from typing import Dict, List, Optional, Set, Tuple, Union

import ccxt
from enforce_typing import enforce_types

from pdr_backend.cli.arg_feed import ArgFeed
from pdr_backend.cli.arg_feeds import ArgFeeds
from pdr_backend.cli.arg_pair import ArgPair
from pdr_backend.subgraph.subgraph_feed import SubgraphFeed
from pdr_backend.util.mocks import MockExchange


class MultiFeedMixin:
Expand Down Expand Up @@ -104,6 +106,14 @@ def __init__(self, d: dict, assert_feed_attributes: Optional[List] = None):
for attr in assert_feed_attributes:
assert getattr(self.feed, attr)

if hasattr(self, "tradetype"):
assert hasattr(self, "allowed_tradetypes")
if self.tradetype not in self.allowed_tradetypes:
raise ValueError(
f"{self.tradetype} not in allowed tradetypes "
f"{', '.join(self.allowed_tradetypes)}"
)

# --------------------------------
# yaml properties
@property
Expand All @@ -114,9 +124,9 @@ def feed(self) -> ArgFeed:
# --------------------------------

@property
def pair_str(self) -> ArgPair:
def pair_str(self) -> str:
"""Return e.g. 'ETH/USDT'. Only applicable when 1 feed."""
return self.feed.pair
return str(self.feed.pair)

@property
def exchange_str(self) -> str:
Expand Down Expand Up @@ -174,3 +184,10 @@ def get_feed_from_candidates(
return feed

return None

@enforce_types
def ccxt_exchange(self, *args, **kwargs) -> ccxt.Exchange:
if not hasattr(self, "tradetype") or self.tradetype != "livemock":
return self.feed.ccxt_exchange(*args, **kwargs)

return MockExchange()
6 changes: 6 additions & 0 deletions pdr_backend/ppss/test/test_trader_ss.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import pytest
from enforce_typing import enforce_types

from pdr_backend.ppss.trader_ss import TraderSS, inplace_make_trader_fast
Expand Down Expand Up @@ -48,6 +49,11 @@ def test_trader_ss():
# str
assert "TraderSS" in str(ss)

bad_dict = _D.copy()
bad_dict["tradetype"] = "xyx"
with pytest.raises(ValueError):
TraderSS(bad_dict)


@enforce_types
def test_inplace_make_trader_fast():
Expand Down
8 changes: 8 additions & 0 deletions pdr_backend/ppss/trader_ss.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ def fee_percent(self) -> str:
def init_holdings_strs(self) -> List[str]:
return self.d["xpmt_only"]["init_holdings"] # eg ["1000 USDT", ..]

@property
def tradetype(self) -> str:
return self.d.get("tradetype", "livemock")

@property
def allowed_tradetypes(self) -> List[str]:
return ["livemock", "livereal"]

# feed defined in base

# --------------------------------
Expand Down
2 changes: 1 addition & 1 deletion pdr_backend/trader/approach1/trader_agent1.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def __init__(self, ppss: PPSS):
super().__init__(ppss)

# Generic exchange class
self.exchange: ccxt.Exchange = self.ppss.trader_ss.feed.ccxt_exchange(
self.exchange: ccxt.Exchange = self.ppss.trader_ss.ccxt_exchange(
{
"apiKey": getenv("EXCHANGE_API_KEY"),
"secret": getenv("EXCHANGE_SECRET_KEY"),
Expand Down
29 changes: 29 additions & 0 deletions pdr_backend/util/mocks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import ccxt


class MockOrder(dict):
def __str__(self):
return f"mocked order: {self.get('amount')} {self['pair_str']}"


class MockExchange(ccxt.Exchange):
def create_market_buy_order(self, pair_str, amount):
return MockOrder(
{
"order_type": "buy",
"amount": str(amount),
"pair_str": pair_str,
}
)

def create_market_sell_order(self, pair_str, position_size):
return MockOrder(
{
"order_type": "sell",
"position_size": str(position_size),
"pair_str": pair_str,
}
)

def __str__(self):
return "mocked exchange"
25 changes: 25 additions & 0 deletions pdr_backend/util/test_noganache/test_mocks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import ccxt

from pdr_backend.util.mocks import MockExchange, MockOrder


def test_mock_order():
mock_order = MockOrder(
{
"order_type": "buy",
"amount": "0.1",
"pair_str": "BTC/USDT",
}
)
assert str(mock_order) == "mocked order: 0.1 BTC/USDT"
assert isinstance(mock_order, dict)


def test_mock_exchange():
mock_exchange = MockExchange()
assert str(mock_exchange) == "mocked exchange"
assert isinstance(mock_exchange, ccxt.Exchange)
assert isinstance(mock_exchange.create_market_buy_order("BTC/USDT", 0.1), MockOrder)
assert isinstance(
mock_exchange.create_market_sell_order("BTC/USDT", 0.1), MockOrder
)

0 comments on commit e3ceba9

Please sign in to comment.