Browse Source

feat: hold

pull/14/head
QuentinN42 1 year ago
parent
commit
e1ee2a4947
Signed by: number42 GPG Key ID: 2CD7D563712B3A50
  1. 35
      auto_trading/interfaces.py
  2. 27
      auto_trading/strat/all_in.py
  3. 41
      auto_trading/strat/hold.py
  4. 25
      tests/interfaces/test_ptf.py
  5. 44
      tests/strat/test_hold.py

35
auto_trading/interfaces.py

@ -12,12 +12,28 @@ from typing import Dict, List, Optional, Any, Callable
from .errors import OrderException, UnknowOrder, PTFException
@dataclass
class PTFState:
"""A fixed state of a PTF (read only)."""
balance: float
stocks: Dict[str, float]
conversion_rate: DataFrame
@property
def total_balance(self) -> float:
conv = self.conversion_rate.to_dict()
return self.balance + sum(
conv[stock_name] * amount for stock_name, amount in self.stocks.items()
)
@dataclass
class Order:
"""An order to execute on a market."""
successfull: Optional[bool] = field(default=None, init=False)
creation_date: datetime
creation_date: datetime = field(default_factory=datetime.now, init=False)
@dataclass
@ -82,12 +98,12 @@ class Strategy(ABC):
indicators: Dict[str, Indicator]
def __init__(self, indicators: Dict[str, Indicator]):
def __init__(self, indicators: Dict[str, Indicator] = None):
"""Init the class with some inticators."""
self.logger = logging.getLogger(self.__class__.__name__)
self.indicators = indicators
self.indicators = indicators or {}
def run(self, data: DataFrame) -> List[Order]:
def run(self, data: DataFrame, state: PTFState) -> List[Order]:
"""Execute the strategy from the data.
Args:
@ -98,10 +114,12 @@ class Strategy(ABC):
List[Order]: A list of orders to execute.
"""
indicators_results: DataFrame = ...
return self.execute(data, indicators_results)
return self.execute(data, indicators_results, state)
@abstractmethod
def execute(self, data: DataFrame, indicators_results: DataFrame) -> List[Order]:
def execute(
self, data: DataFrame, indicators_results: DataFrame, ptf_state: PTFState
) -> List[Order]:
"""Execute the strategy with the indicators insights.
Args:
@ -135,8 +153,13 @@ class PTF(ABC):
self.save_errors = save_errors
@abstractproperty
def state(self) -> PTFState:
"""Return the current state."""
@property
def balance(self) -> float:
"""Return the current total balance."""
return self.state.balance
def execute_multiples(self, orders: List[Order]) -> None:
"""Execute all orders

27
auto_trading/strat/all_in.py

@ -1,27 +0,0 @@
from ..interfaces import Strategy, Portfolio
import numpy as np
class AllIn(Strategy):
"""Just all in the greatest result"""
def __init__(self):
"""Initialise the anti strat"""
def run(self, ptf: Portfolio, result: dict, current_conversion_rate: dict) -> None:
"""Run the strategy"""
# first sell all the stocks
money = 0
for stock, amount in ptf.content().items():
#print(f"{stock}: {amount}")
if amount > 0:
money += current_conversion_rate[stock]*amount
ptf.withdraw(amount, stock)
# after get the greatest result
result = {k:-1 if np.isnan(v) else v for k,v in result.items() }
epsilon = 1e-6
greatest = max(result, key=lambda k: result[k]-(np.inf if current_conversion_rate[k]<epsilon else 0))
# then buy all the greatest result
to_add = money/current_conversion_rate[greatest]
ptf.deposit(to_add, greatest)

41
auto_trading/strat/hold.py

@ -0,0 +1,41 @@
from typing import List
import pandas as pd # type: ignore
from ..orders import Long
from ..interfaces import Strategy, Order, PTFState
class Hold(Strategy):
"""Just hold some stock."""
def __init__(self, to_hold: str):
"""Init the class"""
super().__init__()
self.to_hold = to_hold
def execute(
self, data: pd.DataFrame, indicators_results: pd.DataFrame, state: PTFState
) -> List[Order]:
"""Just hold the value [to_hold].
Args:
data (DataFrame): The Data broker output.
For each time and each stock give (high, low, open, close).
indicators_results (DataFrame): Indicator-Stock valuated float.
For each indicator and each stock give -1 if realy bad and +1 if realy good.
Returns:
List[Order]: A list of orders to execute.
"""
orders = []
# if I have some money
if (balance := state.balance) > 0:
# I calculate the value of the stock
market_price = state.conversion_rate.iloc[-1].to_dict()[self.to_hold]
amount = balance / market_price
# and I buy it all at market price
orders.append(Long(stock=self.to_hold, amount=amount, price=market_price))
return orders # type: ignore

25
tests/interfaces/test_ptf.py

@ -1,18 +1,19 @@
import pytest
from datetime import datetime
from pandas import DataFrame # type: ignore
from auto_trading.errors import UnknowOrder, PTFException
from auto_trading.interfaces import PTF
from auto_trading.interfaces import PTF, PTFState
from auto_trading.orders import Short, Long
long_order = Long(datetime.now(), "BTC", 1, 1)
short_order = Short(datetime.now(), "GOLD", 1, 1)
long_order = Long("BTC", 1, 1)
short_order = Short("GOLD", 1, 1)
class _TestPTFLong(PTF):
@property
def balance(self):
return 0
def state(self):
return PTFState(0, {}, DataFrame())
def execute_long(self, order: Long) -> None:
assert order == long_order
@ -22,8 +23,8 @@ class _TestPTFLong(PTF):
class _TestPTFLongShort(PTF):
@property
def balance(self):
return 0
def state(self):
return PTFState(0, {}, DataFrame())
def execute_long(self, order: Long) -> None:
assert order == long_order
@ -36,8 +37,8 @@ class _TestPTFLongShort(PTF):
class _TestPTFShort(PTF):
@property
def balance(self):
return 0
def state(self):
return PTFState(0, {}, DataFrame())
def execute_short(self, order: Long) -> None:
assert order == short_order
@ -47,8 +48,8 @@ class _TestPTFShort(PTF):
class _TestPTFNone(PTF):
@property
def balance(self):
return 0
def state(self):
return PTFState(0, {}, DataFrame())
@pytest.mark.parametrize(

44
tests/strat/test_hold.py

@ -0,0 +1,44 @@
import pytest
from pandas import DataFrame # type: ignore
from auto_trading.strat.hold import Hold
from auto_trading.interfaces import PTFState as State
from auto_trading.orders import Long
@pytest.mark.parametrize(
"state, output",
[
(State(balance=0, stocks={}, conversion_rate=DataFrame()), None),
(
State(balance=10, stocks={}, conversion_rate=DataFrame({"AAPL": [10]})),
Long(stock="AAPL", amount=1, price=10),
),
(
State(
balance=10,
stocks={"AAPL": 5},
conversion_rate=DataFrame({"AAPL": [10]}),
),
Long(stock="AAPL", amount=1, price=10),
),
(
State(
balance=10,
stocks={"AAPL": 5, "TSLA": 5},
conversion_rate=DataFrame({"AAPL": [10], "TSLA": [20]}),
),
Long(stock="AAPL", amount=1, price=10),
),
],
)
def test_hold(state, output):
strat = Hold(to_hold="AAPL")
res = strat.execute(DataFrame(), DataFrame(), state)
if output is None:
assert len(res) == 0
else:
assert len(res) == 1
assert res[0].stock == output.stock
assert res[0].amount == output.amount
assert res[0].price == output.price
Loading…
Cancel
Save