diff --git a/pytrade/broker.py b/pytrade/broker.py index 48dcda3..8201153 100644 --- a/pytrade/broker.py +++ b/pytrade/broker.py @@ -2,7 +2,7 @@ from pytrade.interfaces.broker import IBroker from pytrade.interfaces.client import IClient -from pytrade.models.instruments import Candlestick, Granularity, Instrument +from pytrade.models.instruments import Candlestick, FxInstrument, Granularity from pytrade.models.order import OrderRequest @@ -35,7 +35,7 @@ def process_orders(self): def subscribe( self, - instrument: Instrument, + instrument: FxInstrument, granularity: Granularity, callback: Callable[[Candlestick], None], ): diff --git a/pytrade/interfaces/broker.py b/pytrade/interfaces/broker.py index c022716..4179fe9 100644 --- a/pytrade/interfaces/broker.py +++ b/pytrade/interfaces/broker.py @@ -1,7 +1,7 @@ import abc from typing import Callable -from pytrade.models.instruments import Candlestick, Granularity, Instrument +from pytrade.models.instruments import Candlestick, FxInstrument, Granularity from pytrade.models.order import OrderRequest @@ -38,7 +38,7 @@ def order(self, order: OrderRequest): @abc.abstractmethod def subscribe( self, - instrument: Instrument, + instrument: FxInstrument, granularity: Granularity, callback: Callable[[Candlestick], None], ): diff --git a/pytrade/interfaces/client.py b/pytrade/interfaces/client.py index 0674e24..791cbd7 100644 --- a/pytrade/interfaces/client.py +++ b/pytrade/interfaces/client.py @@ -3,7 +3,7 @@ from multimethod import multimethod -from pytrade.models.instruments import Candlestick, Granularity, Instrument +from pytrade.models.instruments import Candlestick, FxInstrument, Granularity from pytrade.models.order import MarketOrderRequest @@ -29,20 +29,20 @@ def order(self, order: MarketOrderRequest): @abc.abstractmethod def get_candles( - self, instrument: Instrument, granularity: Granularity, count: int + self, instrument: FxInstrument, granularity: Granularity, count: int ) -> list[Candlestick]: raise NotImplementedError() @abc.abstractmethod def get_candle( - self, instrument: Instrument, granularity: Granularity + self, instrument: FxInstrument, granularity: Granularity ) -> Candlestick: raise NotImplementedError() @abc.abstractmethod def subscribe( self, - instrument: Instrument, + instrument: FxInstrument, granularity: Granularity, callback: Callable[[Candlestick], None], ): diff --git a/pytrade/models/instruments.py b/pytrade/models/instruments.py index fdf06ab..38389cb 100644 --- a/pytrade/models/instruments.py +++ b/pytrade/models/instruments.py @@ -16,6 +16,7 @@ class Granularity(Enum): M15 = "M15" H1 = "H1" H4 = "H4" + D1 = "D1" MINUTES_MAP = { @@ -24,10 +25,11 @@ class Granularity(Enum): Granularity.M15: 15, Granularity.H1: 60, Granularity.H4: 240, + Granularity.D1: 1440, } -class Instrument(Enum): +class FxInstrument(Enum): AUDJPY = "AUD/JPY" AUDNZD = "AUD/NZD" AUDUSD = "AUD/USD" @@ -50,12 +52,12 @@ class Instrument(Enum): USDZAR = "USD/ZAR" -instrument_lookup = {m.value: m for m in Instrument} +instrument_lookup = {m.value: m for m in FxInstrument} class CandleSubscription: - def __init__(self, instrument: Instrument, granularity: Granularity): + def __init__(self, instrument: FxInstrument, granularity: Granularity): self._instrument = instrument self._granularity = granularity @@ -64,7 +66,7 @@ def granularity(self) -> Granularity: return self._granularity @property - def instrument(self) -> Instrument: + def instrument(self) -> FxInstrument: return self._instrument def __hash__(self): @@ -96,7 +98,7 @@ class Candlestick: def __init__( self, - instrument: Instrument, + instrument: FxInstrument, granularity: Granularity, open: float, high: float, @@ -125,7 +127,7 @@ def to_dict(self): class TickData: - instrument: Instrument + instrument: FxInstrument timestamp: datetime bid: float ask: float @@ -161,7 +163,7 @@ def __init__( "Dataframe does not have a datetime index and does not have a 'Timestamp' column" ) self._max_size: Optional[int] = max_size - self.__instrument: Optional[Instrument] = None + self.__instrument: Optional[FxInstrument] = None self.__granularity: Optional[Granularity] = None self.__update_event = Event() @@ -216,7 +218,7 @@ def update(self, candlestick: Candlestick): class CandleData: def __init__(self, max_size=1000): - self._data: dict[tuple[Instrument, Granularity], InstrumentCandles] = {} + self._data: dict[tuple[FxInstrument, Granularity], InstrumentCandles] = {} self._max_size = max_size def __new__(cls, *args, **kwargs): @@ -225,7 +227,7 @@ def __new__(cls, *args, **kwargs): # Need to handle case where instantiatied and different max size is provided return cls.instance - def get(self, instrument: Instrument, granularity: Granularity): + def get(self, instrument: FxInstrument, granularity: Granularity): key = (instrument, granularity) instrument_candles: InstrumentCandles = self._data.get( (instrument, granularity), InstrumentCandles(max_size=self._max_size) diff --git a/pytrade/models/order.py b/pytrade/models/order.py index 5106f1c..0af0572 100644 --- a/pytrade/models/order.py +++ b/pytrade/models/order.py @@ -1,7 +1,7 @@ from enum import Enum from typing import Optional -from pytrade.models.instruments import Instrument +from pytrade.models.instruments import FxInstrument from pytrade.models.trade import Trade @@ -185,7 +185,7 @@ class OrderRequest(dict): def __init__( self, - instrument: Instrument, + instrument: FxInstrument, units: int, time_in_force: TimeInForce, take_profit_on_fill: Optional[float] = None, @@ -201,7 +201,7 @@ def __init__( # stop_loss_on_fill=stop_loss_on_fill, # trailing_stop_loss_on_fill=trailing_stop_loss_on_fill # ) - self._instrument: Instrument = instrument + self._instrument: FxInstrument = instrument self._units: int = units self._time_in_force: Optional[TimeInForce] = time_in_force self._take_profit_on_fill: Optional[float] = take_profit_on_fill @@ -209,7 +209,7 @@ def __init__( self._trailing_stop_loss_on_fill: Optional[float] = trailing_stop_loss_on_fill @property - def instrument(self) -> Instrument: + def instrument(self) -> FxInstrument: return self._instrument @property @@ -241,7 +241,7 @@ class MarketOrderRequest(OrderRequest): def __init__( self, - instrument: Instrument, + instrument: FxInstrument, units: int, time_in_force: TimeInForce = TimeInForce.FILL_OR_KILL, take_profit_on_fill: Optional[float] = None, @@ -272,7 +272,7 @@ class LimitOrderRequest(OrderRequest): def __init__( self, - instrument: Instrument, + instrument: FxInstrument, units: int, price: float, time_in_force: TimeInForce, @@ -295,7 +295,7 @@ class StopOrderRequest(OrderRequest): def __init__( self, - instrument: Instrument, + instrument: FxInstrument, units: int, price: float, time_in_force: TimeInForce, diff --git a/pytrade/strategy.py b/pytrade/strategy.py index 80787bf..6d3d993 100644 --- a/pytrade/strategy.py +++ b/pytrade/strategy.py @@ -7,8 +7,8 @@ CandleData, Candlestick, CandleSubscription, + FxInstrument, Granularity, - Instrument, InstrumentCandles, ) @@ -74,7 +74,7 @@ async def next(self) -> None: self._pending_updates = self._required_updates.copy() def get_data( - self, instrument: Instrument, granularity: Granularity + self, instrument: FxInstrument, granularity: Granularity ) -> InstrumentCandles: return self._data_context.get(instrument, granularity) diff --git a/tests/unit/test_broker.py b/tests/unit/test_broker.py index d85c217..84d195a 100644 --- a/tests/unit/test_broker.py +++ b/tests/unit/test_broker.py @@ -1,7 +1,7 @@ from unittest.mock import Mock from pytrade.broker import FxBroker -from pytrade.models.instruments import Instrument +from pytrade.models.instruments import FxInstrument from pytrade.models.order import OrderRequest, TimeInForce @@ -11,7 +11,7 @@ def test_buy_order(): assert len(broker._pending_orders) == 0 - broker.order(OrderRequest(Instrument.GBPUSD, 10, TimeInForce.GOOD_TILL_CANCELLED)) + broker.order(OrderRequest(FxInstrument.GBPUSD, 10, TimeInForce.GOOD_TILL_CANCELLED)) assert len(broker._pending_orders) == 1 @@ -22,7 +22,9 @@ def test_sell_order(): assert len(broker._pending_orders) == 0 - broker.order(OrderRequest(Instrument.GBPUSD, -10, TimeInForce.GOOD_TILL_CANCELLED)) + broker.order( + OrderRequest(FxInstrument.GBPUSD, -10, TimeInForce.GOOD_TILL_CANCELLED) + ) assert len(broker._pending_orders) == 1 @@ -31,7 +33,7 @@ def test_process_orders(): client = Mock() broker = FxBroker(client) - broker.order(OrderRequest(Instrument.GBPUSD, 10, TimeInForce.GOOD_TILL_CANCELLED)) + broker.order(OrderRequest(FxInstrument.GBPUSD, 10, TimeInForce.GOOD_TILL_CANCELLED)) assert len(broker._pending_orders) == 1 diff --git a/tests/unit/test_indicator.py b/tests/unit/test_indicator.py index b26b1b4..56dab85 100644 --- a/tests/unit/test_indicator.py +++ b/tests/unit/test_indicator.py @@ -7,14 +7,14 @@ from pytrade.models.instruments import ( MINUTES_MAP, Candlestick, + FxInstrument, Granularity, - Instrument, InstrumentCandles, ) def get_candles( - count: int, instrument: Instrument, granularity: Granularity, end_time: datetime + count: int, instrument: FxInstrument, granularity: Granularity, end_time: datetime ) -> list[Candlestick]: _delta = MINUTES_MAP[granularity] return [ @@ -65,7 +65,7 @@ def test_update(): test_series = pd.Series([0, 1, 0, 0, 1]) data = InstrumentCandles() candles = get_candles( - len(test_series), Instrument.EURUSD, Granularity.M1, datetime.now() + len(test_series), FxInstrument.EURUSD, Granularity.M1, datetime.now() ) indicator = BoolIndicator(data) for idx, candle in enumerate(candles): @@ -82,7 +82,7 @@ def test_primitive_equality(): test_series = pd.Series([0, 1, 2, 3, 4]) data = InstrumentCandles() candles = get_candles( - len(test_series), Instrument.EURUSD, Granularity.M1, datetime.now() + len(test_series), FxInstrument.EURUSD, Granularity.M1, datetime.now() ) indicator = SquareIndicator(data) for idx, candle in enumerate(candles): @@ -99,7 +99,7 @@ def test_primitive_greater(): test_series = pd.Series([0, 1, 2, 3, 4]) data = InstrumentCandles() candles = get_candles( - len(test_series), Instrument.EURUSD, Granularity.M1, datetime.now() + len(test_series), FxInstrument.EURUSD, Granularity.M1, datetime.now() ) indicator = StaticIndicator(data) for idx, candle in enumerate(candles): @@ -116,7 +116,7 @@ def test_primitive_less(): test_series = pd.Series([0, 1, 2, 3, 4]) data = InstrumentCandles() candles = get_candles( - len(test_series), Instrument.EURUSD, Granularity.M1, datetime.now() + len(test_series), FxInstrument.EURUSD, Granularity.M1, datetime.now() ) indicator = StaticIndicator(data) for idx, candle in enumerate(candles): @@ -133,7 +133,7 @@ def test_indicator_equality(): test_series = pd.Series([0, 1, 2, 3, 4]) data = InstrumentCandles() candles = get_candles( - len(test_series), Instrument.EURUSD, Granularity.M1, datetime.now() + len(test_series), FxInstrument.EURUSD, Granularity.M1, datetime.now() ) indicator = StaticIndicator(data) indicator2 = StaticIndicator(data) @@ -153,7 +153,7 @@ def test_indicator_greater(): test_series = pd.Series([0, 1, 2, 3, 4]) data = InstrumentCandles() candles = get_candles( - len(test_series), Instrument.EURUSD, Granularity.M1, datetime.now() + len(test_series), FxInstrument.EURUSD, Granularity.M1, datetime.now() ) indicator = StaticIndicator(data) indicator2 = SubtractIndicator(data) @@ -173,7 +173,7 @@ def test_indicator_less(): test_series = pd.Series([0, 1, 2, 3, 4]) data = InstrumentCandles() candles = get_candles( - len(test_series), Instrument.EURUSD, Granularity.M1, datetime.now() + len(test_series), FxInstrument.EURUSD, Granularity.M1, datetime.now() ) indicator = StaticIndicator(data) indicator2 = AddIndicator(data) diff --git a/tests/unit/test_instrument_history.py b/tests/unit/test_instrument_history.py index f731005..87241fd 100644 --- a/tests/unit/test_instrument_history.py +++ b/tests/unit/test_instrument_history.py @@ -10,8 +10,8 @@ INDEX, MINUTES_MAP, Candlestick, + FxInstrument, Granularity, - Instrument, InstrumentCandles, ) @@ -21,7 +21,7 @@ def get_candles(count: int, granularity: Granularity): _delta = MINUTES_MAP[granularity] return [ Candlestick( - Instrument.EURUSD, + FxInstrument.EURUSD, granularity, random.uniform(0, 10), random.uniform(0, 10), @@ -121,7 +121,7 @@ def test_update_wrong_instrument(): history = InstrumentCandles(max_size=10) first_candle = dummy_candles[0] second_candle = dummy_candles[1] - second_candle.instrument = Instrument.GBPUSD + second_candle.instrument = FxInstrument.GBPUSD assert first_candle.instrument != second_candle.instrument diff --git a/tests/unit/test_strategy.py b/tests/unit/test_strategy.py index 5cc2049..a307e1c 100644 --- a/tests/unit/test_strategy.py +++ b/tests/unit/test_strategy.py @@ -11,32 +11,32 @@ CandleData, Candlestick, CandleSubscription, + FxInstrument, Granularity, - Instrument, ) from pytrade.strategy import FxStrategy TEST_SUBCRIPTIONS = [ - CandleSubscription(Instrument.EURUSD, Granularity.M5), - CandleSubscription(Instrument.EURUSD, Granularity.M15), - CandleSubscription(Instrument.GBPUSD, Granularity.M5), - CandleSubscription(Instrument.GBPUSD, Granularity.M15), + CandleSubscription(FxInstrument.EURUSD, Granularity.M5), + CandleSubscription(FxInstrument.EURUSD, Granularity.M15), + CandleSubscription(FxInstrument.GBPUSD, Granularity.M5), + CandleSubscription(FxInstrument.GBPUSD, Granularity.M15), ] TEST_UPDATES = [ - CandleSubscription(Instrument.EURUSD, Granularity.M5), - CandleSubscription(Instrument.EURUSD, Granularity.M5), - CandleSubscription(Instrument.EURUSD, Granularity.M5), - CandleSubscription(Instrument.EURUSD, Granularity.M15), - CandleSubscription(Instrument.GBPUSD, Granularity.M5), - CandleSubscription(Instrument.GBPUSD, Granularity.M5), - CandleSubscription(Instrument.GBPUSD, Granularity.M5), - CandleSubscription(Instrument.GBPUSD, Granularity.M15), + CandleSubscription(FxInstrument.EURUSD, Granularity.M5), + CandleSubscription(FxInstrument.EURUSD, Granularity.M5), + CandleSubscription(FxInstrument.EURUSD, Granularity.M5), + CandleSubscription(FxInstrument.EURUSD, Granularity.M15), + CandleSubscription(FxInstrument.GBPUSD, Granularity.M5), + CandleSubscription(FxInstrument.GBPUSD, Granularity.M5), + CandleSubscription(FxInstrument.GBPUSD, Granularity.M5), + CandleSubscription(FxInstrument.GBPUSD, Granularity.M15), ] def get_candles( - count: int, instrument: Instrument, granularity: Granularity, end_time: datetime + count: int, instrument: FxInstrument, granularity: Granularity, end_time: datetime ) -> list[Candlestick]: _delta = MINUTES_MAP[granularity] return [