def _quote_of(dt: datetime, data: dict) -> Quote: return Quote(dt=dt, asset=Asset.of(data['ticker']), bid=data['bid'], ask=data['ask'], last=data['last'], last_change=data['last_change'])
def _ohlcv_of(dt: datetime, data: dict) -> Ohlcv: return Ohlcv(dt=dt, asset=Asset.of(data['ticker']), o=data['open'], h=data['high'], l=data['low'], c=data['close'], v=data['volume'])
def _level2_of(data) -> Level2: dt = pd.to_datetime(data[0][0]) asset = Asset.of(data[0][1]) # Price, bid, ask level2_items = [ Level2Item(data_item[2], data_item[3], data_item[4]) for data_item in data ] return Level2(dt, asset, level2_items)
def test__quote_of(self): # Set input dt = datetime.now() data = { 'ticker': str(Asset("stock1", "name1")), 'bid': 1, 'ask': 2, 'last': 3, 'last_change': 4 } # Call quote = CsvFeedConnector._quote_of(dt, data) # Assert self.assertEqual(quote.dt, dt) self.assertEqual(quote.asset, Asset.of(data['ticker'])) self.assertEqual(quote.bid, data['bid']) self.assertEqual(quote.ask, data['ask']) self.assertEqual(quote.last, data['last']) self.assertEqual(quote.last_change, data['last_change'])
def test__ohlcv_of(self): # Set input dt = datetime.now() data = { 'ticker': str(Asset("stock1", "name1")), 'open': 1, 'high': 2, 'low': 3, 'close': 4, 'volume': 5 } # Call candle = CsvFeedConnector._ohlcv_of(dt, data) # Assert self.assertEqual(candle.dt, dt) self.assertEqual(candle.asset, Asset.of(data['ticker'])) self.assertEqual(candle.o, data['open']) self.assertEqual(candle.h, data['high']) self.assertEqual(candle.l, data['low']) self.assertEqual(candle.c, data['close']) self.assertEqual(candle.v, data['volume'])
def run(self): # Read csvs to dataframes self.read_csvs() self._logger.info("Producing the data from csvs") # Merge all datetimes ticks = pd.concat([ self.quotes.index.to_series(), self.candles.index.to_series(), self.level2['datetime'] ]).sort_values() # Process each time tick and produce candle, level2 or quote for dt, tick in ticks.iteritems(): # Produce next quote if tick in self.quotes.index: quote_dict = self.quotes.iloc[self.quotes.index.get_loc( dt)].to_dict() quote = self._quote_of(dt, quote_dict) for subscriber in self._feed_subscribers[ quote.asset] + self._feed_subscribers[ Asset.any_asset()]: subscriber.on_quote(quote) # Produce next candle if tick in self.candles.index: candle_dict = self.candles.iloc[self.candles.index.get_loc( dt)].to_dict() candle = self._ohlcv_of(dt, candle_dict) for subscriber in self._feed_subscribers[ candle.asset] + self._feed_subscribers[ Asset.any_asset()]: subscriber.on_candle(candle) # Produce next level2 level2_items = self.level2[self.level2['datetime'] == tick].to_numpy() if level2_items.size > 0: level2 = CsvFeedConnector._level2_of(level2_items) for subscriber in self._feed_subscribers[ level2.asset] + self._feed_subscribers[ Asset.any_asset()]: subscriber.on_level2(level2)
def on_quote(self, quote: Quote): """ New bid/ask received """ self.last_tick_time = datetime.now() self._logger.debug(f"Received quote, asset: {quote.asset}, quote: {quote}") # Set to quotes pandas dataframe self.quotes.at[(quote.dt, str(quote.asset)), ['bid', 'ask', 'last']] = [quote.bid, quote.ask, quote.last] # Push the quote up to subscribers subscribers = self._subscribers[quote.asset] + self._subscribers[Asset("*", "*")] push_list = set(filter(lambda s: callable(getattr(s, 'on_quote', None)), subscribers)) for subscriber in push_list: subscriber.on_quote(quote)
def on_candle(self, ohlcv: Ohlcv): """ New ohlc data received """ # Add ohlc to data self.candles.at[(ohlcv.dt, str(ohlcv.asset)), ['open', 'high', 'low', 'close', 'volume']] = [ohlcv.o, ohlcv.h, ohlcv.l, ohlcv.c, ohlcv.v] self._logger.debug(f"Received candle for asset {ohlcv.asset}, candle: {ohlcv}") # Push data to subscribers subscribers = self._subscribers[ohlcv.asset] + self._subscribers[Asset("*", "*")] push_list = set(filter(lambda s: callable(getattr(s, 'on_candle', None)), subscribers)) for subscriber in push_list: subscriber.on_candle(ohlcv) self.last_tick_time = datetime.now()
def on_level2(self, level2: Level2): """ New level2 data received """ self._logger.debug(f"Received level2 {level2}") asset_str = str(level2.asset) # Add new level2 records to dataframe for item in level2.items: self.level2 = self.level2.append({'datetime': level2.dt, 'ticker': asset_str, 'price': item.price, 'ask_vol': item.ask_vol, 'bid_vol': item.bid_vol}, ignore_index=True) # self.level2.at[(level2.dt, asset_str, item.price),['datetime','bid_vol', 'ask_vol','price']] = [level2.dt, item.price,item.bid_vol, item.ask_vol] # Push level2 event up subscribers = self._subscribers[level2.asset] + self._subscribers[Asset("*", "*")] push_list = set(filter(lambda s: callable(getattr(s, 'on_level2', None)), subscribers)) for subscriber in push_list: subscriber.on_level2(level2)
def __init__(self, feed: Feed, broker: Broker, config): self._logger = logging.getLogger(__name__) self._feed = feed self._broker = broker self.asset = Asset(config['trade.asset.sec_class'], config['trade.asset.sec_code']) # self._last_big_learn_time = datetime.min self._last_learn_time = None # todo:: parameterise self._interval_big_learn = timedelta(seconds=10) self._interval_small_learn = timedelta(hours=2) self._csv_connector = CsvFeedConnector(config) self._feed.subscribe_feed(self.asset, self) self._logger.info( f"Strategy initialized with initial learn interval {self._interval_big_learn}," f" additional learn interval ${self._interval_small_learn}")
def __init__(self, feed, rabbit_host: str): self._logger = logging.getLogger(__name__) self._feed = feed # Subscribe to feed self.callbacks = { # MsgId.QUOTES: self._on_quotes, MsgId.GRAPH: self.on_candle, # MsgId.LEVEL2: self._on_level2, } self._feed.subscribe_feed(Asset.any_asset(), self) # Init rabbitmq connection self._logger.info(f"Connecting to rabbit host {rabbit_host}") self._rabbit_connection = pika.BlockingConnection( pika.ConnectionParameters(rabbit_host)) self._rabbit_channel = self._rabbit_connection.channel() for q in [QueueName.CANDLES]: self._logger.info(f"Declaring rabbit queue {q}") self._rabbit_channel.queue_declare(queue=q, durable=True)
def test_level2_of(self): # Set input dt = datetime.fromisoformat("2021-11-14 10:00") data = { 'datetime': [dt, dt], 'ticker': ['stock1/ticker1', 'stock1/ticker1'], 'price': [1, 11], 'bid_vol': [2, 22], 'ask_vol': [3, 33] } data = pd.DataFrame(data).to_numpy() # Process level2 = CsvFeedConnector._level2_of(data) # Assert self.assertEqual(level2.asset, Asset("stock1", "ticker1")) self.assertEqual(level2.dt, dt) self.assertEqual([item.price for item in level2.items], [1, 11]) self.assertEqual([item.bid_vol for item in level2.items], [2, 22]) self.assertEqual([item.ask_vol for item in level2.items], [3, 33])