async def tick( self) -> AsyncGenerator[Any, Event]: # type: ignore[override] now = self._start for i in range(1000): if self._client_order: self._client_order.filled = self._client_order.volume t = Trade( self._client_order.volume, i, taker_order=self._client_order, maker_orders=[], ) t.taker_order.timestamp = now self._client_order = None yield Event(type=EventType.TRADE, target=t) continue o = Order( 1, i, Side.BUY, self._instrument, self.exchange(), timestamp=now, filled=1, ) t = Trade(1, i, o, []) yield Event(type=EventType.TRADE, target=t) now += timedelta(minutes=30)
async def tick(self): '''return data from exchange''' while True: # clear order events while self._order_event_queue.qsize() > 0: order_data = self._order_event_queue.get() status = order_data['status'] order = self._orders[order_data['orderId']] if status in ('ApiPending', 'PendingSubmit', 'PendingCancel', 'PreSubmitted', 'ApiCancelled', 'Inactive'): # ignore continue elif status in ('Submitted', ): # TODO more granular order events api? # ignore pass elif status in ('Cancelled', ): e = Event(type=EventType.REJECTED, target=order) yield e elif status in ('Filled', ): t = Trade(volume=order_data['filled'], price=order_data['avgFillPrice'], maker_orders=[], taker_order=order) t.my_order = order e = Event(type=EventType.TRADE, target=t) yield e await asyncio.sleep(0)
async def tick(self): '''return data from exchange''' while True: # clear order events while self._order_event_queue.qsize() > 0: order_data = self._order_event_queue.get() status = order_data['status'] order = self._orders[order_data['orderId']] if status in ('ApiPending', 'PendingSubmit', 'PendingCancel', 'PreSubmitted', 'ApiCancelled', 'Inactive'): # ignore continue elif status in ('Submitted',): e = Event(type=EventType.RECEIVED, target=order) yield e elif status in ('Cancelled',): e = Event(type=EventType.CANCELED, target=order) yield e elif status in ('Filled',): # this is the filled from orderStatus, but we # want to use the one from execDetails # From the IB Docs: # "There are not guaranteed to be orderStatus # callbacks for every change in order status" # It is recommended to use execDetails # ignore pass elif status in ('Execution',): # set filled order.filled = order_data['filled'] # create trade object t = Trade(volume=order_data['filled'], price=order_data['avgFillPrice'], maker_orders=[], taker_order=order) # set my order t.my_order = order e = Event(type=EventType.TRADE, target=t) yield e # clear market data events while self._market_data_queue.qsize() > 0: market_data = self._market_data_queue.get() instrument = market_data['instrument'] price = market_data['price'] o = Order(volume=1, price=price, side=Side.BUY, instrument=instrument, exchange=self.exchange()) t = Trade(volume=1, price=price, taker_order=o, maker_orders=[]) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0)
async def tick(self): '''return data from exchange''' while True: # clear order events while self._order_event_queue.qsize() > 0: order_data = self._order_event_queue.get() status = order_data['status'] order = self._orders[order_data['orderId']] if status in ('ApiPending', 'PendingSubmit', 'PendingCancel', 'PreSubmitted', 'ApiCancelled', 'Inactive'): # ignore continue elif status in ('Submitted', ): # TODO more granular order events api? # ignore pass elif status in ('Cancelled', ): e = Event(type=EventType.CANCELED, target=order) yield e elif status in ('Filled', ): # set filled order.filled = order_data['filled'] # create trade object t = Trade(volume=order_data['filled'], price=order_data['avgFillPrice'], maker_orders=[], taker_order=order) # set my order t.my_order = order e = Event(type=EventType.TRADE, target=t) yield e # clear market data events while self._market_data_queue.qsize() > 0: market_data = self._market_data_queue.get() instrument = market_data['instrument'] price = market_data['price'] o = Order(volume=1, price=price, side=Side.BUY, instrument=instrument, exchange=self.exchange()) t = Trade(volume=1, price=price, taker_order=o, maker_orders=[]) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0)
async def connect(self) -> None: with open(self._filename) as csvfile: self._reader = csv.DictReader(csvfile, delimiter=",") for row in self._reader: order = Order( volume=float(row["volume"]), price=float(row["close"]), side=Side.BUY, exchange=self.exchange(), instrument=Instrument( row["symbol"].split("-")[0], InstrumentType(row["symbol"].split("-")[1].upper()), ), filled=float(row["volume"]), ) if "time" in row: order.timestamp = datetime.fromtimestamp(float( row["time"])) elif "date" in row: order.timestamp = datetime.fromisoformat(row["date"]) elif "datetime" in row: order.timestamp = datetime.fromisoformat(row["datetime"]) self._data.append( Trade( volume=float(row["volume"]), price=float(row["close"]), maker_orders=[], taker_order=order, ))
async def connect(self): with open(self._filename) as csvfile: self._reader = csv.DictReader(csvfile, delimiter=',') for row in self._reader: order = Order(volume=float(row['volume']), price=float(row['close']), side=Side.BUY, exchange=self.exchange(), instrument=Instrument( row['symbol'].split('-')[0], InstrumentType(row['symbol'].split('-')[1].upper()) ) ) order.filled = float(row['volume']) if 'time' in row: order.timestamp = datetime.fromtimestamp(float(row['time'])) elif 'date' in row: order.timestamp = datetime.fromisoformat(row['date']) elif 'datetime' in row: order.timestamp = datetime.fromisoformat(row['datetime']) self._data.append(Trade(volume=float(row['volume']), price=float(row['close']), maker_orders=[], taker_order=order))
def restore(self, filename_prefix): with open('{}.prices.json'.format(filename_prefix), 'r') as fp: jsn = json.load(fp) self._prices = { Instrument.fromJson(json.loads(k)): [(p1, datetime.fromtimestamp(p2)) for p1, p2 in v] for k, v in jsn.items() } with open('{}.trades.json'.format(filename_prefix), 'r') as fp: jsn = json.load(fp) self._trades = { Instrument.fromJson(json.loads(k)): [Trade.fromJson(x) for x in v] for k, v in jsn.items() } with open('{}.active_by_inst.json'.format(filename_prefix), 'r') as fp: jsn = json.load(fp) self._active_positions_by_instrument = { Instrument.fromJson(json.loads(k)): [Position.fromJson(vv) for vv in v] for k, v in jsn.items() } with open('{}.active_by_strat.json'.format(filename_prefix), 'r') as fp: jsn = json.load(fp) self._active_positions_by_strategy = { k: { Instrument.fromJson(json.loads(kk)): Position.fromJson(vv) for kk, vv in v.items() } for k, v in jsn.items() }
async def tick(self): now = self._start for i in range(1000): if self._client_order: self._client_order.filled = self._client_order.volume t = Trade(self._client_order.volume, i, [], self._client_order) t.taker_order.timestamp = now self._client_order = None yield Event(type=EventType.TRADE, target=t) continue o = Order(1, i, Side.BUY, self._instrument, self.exchange()) o.filled = 1 o.timestamp = now t = Trade(1, i, [], o) yield Event(type=EventType.TRADE, target=t) now += timedelta(minutes=30)
def test_maker_orders_validation(self): if not os.environ.get('AAT_USE_CPP'): with pytest.raises(Exception): o = Order(volume=0.0, price=5.0, side=Order.Sides.SELL, order_type=Order.Types.LIMIT, exchange=ExchangeType(''), instrument=_INSTRUMENT) Trade(maker_orders=deque(), taker_order=o)
async def tick(self): '''return data from exchange''' dfs = [] for i in self._subscriptions: df = self._client.chartDF(i.name, timeframe='6m') df = df[['close', 'volume']] df.columns = ['close:{}'.format(i.name), 'volume:{}'.format(i.name)] dfs.append(df) data = pd.concat(dfs, axis=1) data.sort_index(inplace=True) data = data.groupby(data.index).last() data.drop_duplicates(inplace=True) data.fillna(method='ffill', inplace=True) for index in data.index: for i in self._subscriptions: volume = data.loc[index]['volume:{}'.format(i.name)] price = data.loc[index]['close:{}'.format(i.name)] o = Order(volume=volume, price=price, side=Side.BUY, instrument=i, exchange=self.exchange()) o.timestamp = index.to_pydatetime() t = Trade(volume=volume, price=price, taker_order=o, maker_orders=[]) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0) while self._queued_orders: order = self._queued_orders.popleft() order.timestamp = index t = Trade(volume=order.volume, price=order.price, taker_order=order, maker_orders=[]) t.my_order = order yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0)
def test_maker_orders_validation(self): if not os.environ.get('AAT_USE_CPP'): with pytest.raises(pydantic.ValidationError): o = Order(id=1, timestamp=datetime.now(), volume=0.0, price=5.0, side=Order.Sides.SELL, order_type=Order.Types.LIMIT, exchange=ExchangeType(''), instrument=_INSTRUMENT) Trade(id=1, timestamp=datetime.now(), volume=0.0, price=0.0, side=Order.Sides.SELL, exchange=ExchangeType(''), instrument=_INSTRUMENT, maker_orders=deque(), taker_order=o)
async def tick(self): for item in self._data: yield Event(EventType.TRADE, item) await asyncio.sleep(0) # save timestamp timestamp = item.timestamp while self._queued_orders: order = self._queued_orders.popleft() order.timestamp = timestamp order.filled = order.volume t = Trade( volume=order.volume, price=order.price, taker_order=order, maker_orders=[], my_order=order, ) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0)
async def tick( self) -> AsyncGenerator[Any, Event]: # type: ignore[override] """return data from exchange""" while True: # clear order events while self._order_event_queue.qsize() > 0: order_data = self._order_event_queue.get() status = order_data["status"] order = self._orders[str(order_data["orderId"])] if status in ( "ApiPending", "PendingSubmit", "PendingCancel", "PreSubmitted", "ApiCancelled", "Inactive", ): # ignore continue elif status in ("Submitted", ): self._order_received_res[order.id] = True self._order_received_map[order.id].set() await asyncio.sleep(0) elif status in ("Cancelled", ): self._order_cancelled_res[order.id] = True self._order_cancelled_map[order.id].set() await asyncio.sleep(0) elif status in ("Filled", ): # this is the filled from orderStatus, but we # want to use the one from execDetails # From the IB Docs: # "There are not guaranteed to be orderStatus # callbacks for every change in order status" # It is recommended to use execDetails # ignore pass elif status in ("Execution", ): # set filled order.filled = order_data["filled"] # create trade object t = Trade( volume=order_data["filled"], # type: ignore price=order_data["avgFillPrice"], # type: ignore maker_orders=[], taker_order=order, ) # set my order t.my_order = order e = Event(type=EventType.TRADE, target=t) yield e # clear market data events while self._market_data_queue.qsize() > 0: market_data = self._market_data_queue.get() instrument: Instrument = market_data[ "instrument"] # type: ignore price: float = market_data["price"] # type: ignore o = AATOrder( volume=1, price=price, side=Side.BUY, instrument=instrument, exchange=self.exchange(), ) t = Trade(volume=1, price=float(price), taker_order=o, maker_orders=[]) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0)
async def tick(self): '''return data from exchange''' if self._timeframe == 'live': data = deque() def _callback(record): data.append(record) self._client.tradesSSE(symbols=",".join( [i.name for i in self._subscriptions]), on_data=_callback) while True: while data: record = data.popleft() volume = record['volume'] price = record['price'] instrument = Instrument(record['symbol'], InstrumentType.EQUITY) o = Order(volume=volume, price=price, side=Side.BUY, instrument=instrument, exchange=self.exchange()) t = Trade(volume=volume, price=price, taker_order=o, maker_orders=[]) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0) else: dfs = [] insts = set() if self._timeframe != '1d': for i in tqdm(self._subscriptions, desc="Fetching data..."): if i.name in insts: # already fetched the data, multiple subscriptions continue if self._cache_data: # first, check if we have this data and its cached already os.makedirs('_aat_data', exist_ok=True) data_filename = os.path.join( '_aat_data', 'iex_{}_{}_{}_{}.pkl'.format( i.name, self._timeframe, datetime.now().strftime('%Y%m%d'), 'sand' if self._is_sandbox else '')) if os.path.exists(data_filename): print('using cached IEX data for {}'.format( i.name)) df = pd.read_pickle(data_filename) else: df = self._client.chartDF( i.name, timeframe=self._timeframe) df.to_pickle(data_filename) else: df = self._client.chartDF(i.name, timeframe=self._timeframe) df = df[['close', 'volume']] df.columns = [ 'close:{}'.format(i.name), 'volume:{}'.format(i.name) ] dfs.append(df) insts.add(i.name) data = pd.concat(dfs, axis=1) data.sort_index(inplace=True) data = data.groupby(data.index).last() data.drop_duplicates(inplace=True) data.fillna(method='ffill', inplace=True) else: for i in tqdm(self._subscriptions, desc="Fetching data..."): if i.name in insts: # already fetched the data, multiple subscriptions continue date = self._start_date subdfs = [] while date <= self._end_date: if self._cache_data: # first, check if we have this data and its cached already os.makedirs('_aat_data', exist_ok=True) data_filename = os.path.join( '_aat_data', 'iex_{}_{}_{}_{}.pkl'.format( i.name, self._timeframe, date, 'sand' if self._is_sandbox else '')) if os.path.exists(data_filename): print( 'using cached IEX data for {} - {}'.format( i.name, date)) df = pd.read_pickle(data_filename) else: df = self._client.chartDF( i.name, timeframe='1d', date=date.strftime('%Y%m%d')) df.to_pickle(data_filename) else: df = self._client.chartDF( i.name, timeframe='1d', date=date.strftime('%Y%m%d')) if not df.empty: df = df[['average', 'volume']] df.columns = [ 'close:{}'.format(i.name), 'volume:{}'.format(i.name) ] subdfs.append(df) date += timedelta(days=1) dfs.append(pd.concat(subdfs)) insts.add(i.name) data = pd.concat(dfs, axis=1) data.index = [ x + timedelta(hours=int(y.split(':')[0]), minutes=int(y.split(':')[1])) for x, y in data.index ] data = data.groupby(data.index).last() data.drop_duplicates(inplace=True) data.fillna(method='ffill', inplace=True) for index in data.index: for i in self._subscriptions: volume = data.loc[index]['volume:{}'.format(i.name)] price = data.loc[index]['close:{}'.format(i.name)] if volume == 0: continue o = Order(volume=volume, price=price, side=Side.BUY, instrument=i, exchange=self.exchange()) o.filled = volume o.timestamp = index.to_pydatetime() t = Trade(volume=volume, price=price, taker_order=o, maker_orders=[]) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0) while self._queued_orders: order = self._queued_orders.popleft() order.timestamp = index order.filled = order.volume t = Trade(volume=order.volume, price=order.price, taker_order=order, maker_orders=[]) t.my_order = order yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0)
async def tick( self) -> AsyncGenerator[Any, Event]: # type: ignore[override] """return data from exchange""" while True: # clear order events while self._order_event_queue.qsize() > 0: try: order_data = self._order_event_queue.get_nowait() except Empty: await asyncio.sleep(0.1) continue status = order_data["status"] order = self._orders[str(order_data["orderId"])] if status in ( "ApiPending", "PendingSubmit", "PendingCancel", "PreSubmitted", "ApiCancelled", ): # ignore continue elif status in ("Inactive", ): self._finished_orders.add(order.id) self._send_order_received(order.id, False) self._send_cancel_received(order.id, False) elif status in ("Rejected", ): self._finished_orders.add(order.id) self._send_order_received(order.id, False) await asyncio.sleep(0) elif status in ("Submitted", ): self._send_order_received(order.id, True) await asyncio.sleep(0) elif status in ("Cancelled", ): self._finished_orders.add(order.id) self._send_cancel_received(order.id, True) await asyncio.sleep(0) elif status in ("Filled", ): # this is the filled from orderStatus, but we # want to use the one from execDetails # From the IB Docs: # "There are not guaranteed to be orderStatus # callbacks for every change in order status" # It is recommended to use execDetails # ignore pass elif status in ("Execution", ): # set filled order.filled = order_data["filled"] # finish order if fully filled if order.finished(): self._finished_orders.add(order.id) # if it was cancelled but already executed, clear out the wait self._send_cancel_received(order.id, False) # create trade object t = Trade( volume=order_data["filled"], # type: ignore price=order_data["avgFillPrice"], # type: ignore maker_orders=[], taker_order=order, ) # set my order t.my_order = order e = Event(type=EventType.TRADE, target=t) # if submitted was skipped, clear out the wait self._send_order_received(order.id, True) yield e # clear market data events while self._market_data_queue.qsize() > 0: try: market_data = self._market_data_queue.get_nowait() except Empty: await asyncio.sleep(0.1) continue instrument: Instrument = market_data[ "instrument"] # type: ignore price: float = market_data["price"] # type: ignore o = AATOrder( volume=1, price=price, side=Side.BUY, instrument=instrument, exchange=self.exchange(), filled=1, ) t = Trade(volume=1, price=float(price), taker_order=o, maker_orders=[]) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0)
async def tick( self) -> AsyncGenerator[Any, Event]: # type: ignore[override] """return data from exchange""" if self._timeframe == "live": data: Deque[dict] = deque() def _callback(record: dict) -> None: data.append(record) self._client.tradesSSE( symbols=",".join([i.name for i in self._subscriptions]), on_data=_callback, ) while True: while data: record = data.popleft() volume = record["volume"] price = record["price"] instrument = Instrument(record["symbol"], InstrumentType.EQUITY) o = Order( volume=volume, price=price, side=Side.BUY, instrument=instrument, exchange=self.exchange(), ) t = Trade(volume=volume, price=price, taker_order=o, maker_orders=[]) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0) else: dfs = [] insts = set() if self._timeframe != "1d": for i in tqdm(self._subscriptions, desc="Fetching data..."): if i.name in insts: # already fetched the data, multiple subscriptions continue if self._cache_data: # first, check if we have this data and its cached already os.makedirs("_aat_data", exist_ok=True) data_filename = os.path.join( "_aat_data", "iex_{}_{}_{}_{}.pkl".format( i.name, self._timeframe, datetime.now().strftime("%Y%m%d"), "sand" if self._is_sandbox else "", ), ) if os.path.exists(data_filename): print("using cached IEX data for {}".format( i.name)) df = pd.read_pickle(data_filename) else: df = self._client.chartDF( i.name, timeframe=self._timeframe) df.to_pickle(data_filename) else: df = self._client.chartDF(i.name, timeframe=self._timeframe) df = df[["close", "volume"]] df.columns = [ "close:{}".format(i.name), "volume:{}".format(i.name) ] dfs.append(df) insts.add(i.name) data_frame = pd.concat(dfs, axis=1) data_frame.sort_index(inplace=True) data_frame = data_frame.groupby(data_frame.index).last() data_frame.drop_duplicates(inplace=True) data_frame.fillna(method="ffill", inplace=True) else: for i in tqdm(self._subscriptions, desc="Fetching data..."): if i.name in insts: # already fetched the data, multiple subscriptions continue date = self._start_date subdfs = [] while date <= self._end_date: if self._cache_data: # first, check if we have this data and its cached already os.makedirs("_aat_data", exist_ok=True) data_filename = os.path.join( "_aat_data", "iex_{}_{}_{}_{}.pkl".format( i.name, self._timeframe, date, "sand" if self._is_sandbox else "", ), ) if os.path.exists(data_filename): print( "using cached IEX data for {} - {}".format( i.name, date)) df = pd.read_pickle(data_filename) else: df = self._client.chartDF( i.name, timeframe="1d", date=date.strftime("%Y%m%d")) df.to_pickle(data_filename) else: df = self._client.chartDF( i.name, timeframe="1d", date=date.strftime("%Y%m%d")) if not df.empty: df = df[["average", "volume"]] df.columns = [ "close:{}".format(i.name), "volume:{}".format(i.name), ] subdfs.append(df) date += timedelta(days=1) dfs.append(pd.concat(subdfs)) insts.add(i.name) data_frame = pd.concat(dfs, axis=1) data_frame.index = [ x + timedelta(hours=int(y.split(":")[0]), minutes=int(y.split(":")[1])) for x, y in data_frame.index ] data_frame = data_frame.groupby(data_frame.index).last() data_frame.drop_duplicates(inplace=True) data_frame.fillna(method="ffill", inplace=True) for index in data_frame.index: for i in self._subscriptions: volume = data_frame.loc[index]["volume:{}".format(i.name)] price = data_frame.loc[index]["close:{}".format(i.name)] if volume == 0: continue o = Order( volume=volume, price=price, side=Side.BUY, instrument=i, exchange=self.exchange(), filled=volume, timestamp=index.to_pydatetime(), ) t = Trade(volume=volume, price=price, taker_order=o, maker_orders=[]) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0) while self._queued_orders: order = self._queued_orders.popleft() order.timestamp = index order.filled = order.volume t = Trade( volume=order.volume, price=order.price, taker_order=order, maker_orders=[], my_order=order, ) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0)
async def tick(self): '''return data from exchange''' if self._timeframe == 'live': data = deque() def _callback(record): data.append(record) self._client.tradesSSE(symbols=",".join([i.name for i in self._subscriptions]), on_data=_callback) while True: while data: record = data.popleft() volume = record['volume'] price = record['price'] instrument = Instrument(record['symbol'], InstrumentType.EQUITY) o = Order(volume=volume, price=price, side=Side.BUY, instrument=instrument, exchange=self.exchange()) t = Trade(volume=volume, price=price, taker_order=o, maker_orders=[]) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0) else: dfs = [] if self._timeframe != '1d': for i in tqdm(self._subscriptions, desc="Fetching data..."): df = self._client.chartDF(i.name, timeframe=self._timeframe) df = df[['close', 'volume']] df.columns = ['close:{}'.format(i.name), 'volume:{}'.format(i.name)] dfs.append(df) data = pd.concat(dfs, axis=1) data.sort_index(inplace=True) data = data.groupby(data.index).last() data.drop_duplicates(inplace=True) data.fillna(method='ffill', inplace=True) else: for i in tqdm(self._subscriptions, desc="Fetching data..."): date = self._start_date subdfs = [] while date <= self._end_date: df = self._client.chartDF(i.name, timeframe='1d', date=date.strftime('%Y%m%d')) if not df.empty: df = df[['average', 'volume']] df.columns = ['close:{}'.format(i.name), 'volume:{}'.format(i.name)] subdfs.append(df) date += timedelta(days=1) dfs.append(pd.concat(subdfs)) data = pd.concat(dfs, axis=1) data.index = [x + timedelta(hours=int(y.split(':')[0]), minutes=int(y.split(':')[1])) for x, y in data.index] data = data.groupby(data.index).last() data.drop_duplicates(inplace=True) data.fillna(method='ffill', inplace=True) for index in data.index: for i in self._subscriptions: volume = data.loc[index]['volume:{}'.format(i.name)] price = data.loc[index]['close:{}'.format(i.name)] if volume == 0: continue o = Order(volume=volume, price=price, side=Side.BUY, instrument=i, exchange=self.exchange()) o.timestamp = index.to_pydatetime() t = Trade(volume=volume, price=price, taker_order=o, maker_orders=[]) yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0) while self._queued_orders: order = self._queued_orders.popleft() order.timestamp = index t = Trade(volume=order.volume, price=order.price, taker_order=order, maker_orders=[]) t.my_order = order yield Event(type=EventType.TRADE, target=t) await asyncio.sleep(0)