async def on_parameters(self, parameters): delta_crypto = parameters['change_crypto'] delta_cash = parameters['change_cash'] if (delta_cash != 0 or delta_crypto != 0): self._pnl_manager.update_reserves(delta_cash, delta_crypto) # Reset the change parameters parameters['change_crypto'] = 0 parameters['change_cash'] = 0 self._pnl_manager.update_refresh_interval(parameters['state_refresh']) # TODO: Validate parameters log.info('Updating strategy parameters from: {} to {}', self._params, parameters) old_params = self._params self._params = parameters if (self._prev_book is not None) and self._trader._session.open_orders: # We have orders in the market, and parameters were changed by # the user. Recompute and update orders if old_params['orders'] != self._params['orders']: # Cancel all existing orders and recreate the orders # TODO: come up with a better way that doesn't require # cancelling all orders. # Perhaps implement revises await self._trader.cancel_session() await self.create_orders(self._prev_book) else: await self.update_orders(self._prev_book)
def main(args): params = { 'api_url': gdax.OrderEntryGateway.SANDBOX_URL, 'api_key': args['<API_KEY>'], 'api_secret': args['<API_SECRET>'], 'passphrase': args['<PASSPHRASE>'], 'ip': args['<IP>'], 'port': args['<PORT>'], 'sandbox': False if (args['<SANDBOX>'] == "False") else True, 'instrument': args['<INSTRUMENT>'] } log.info('Starting Anchor Strategy for {} in {} mode', params['instrument'], 'SANDBOX' if params['sandbox'] else 'PRODUCTION') # TODO: Set up limits through configuration StrategyConfig['limits'] = {} StrategyConfig['limits']['max_order_qty'] = make_qty('2') StrategyConfig['limits']['max_order_value'] = make_price('1000') StrategyConfig['limits']['max_open_value'] = 1000 loop = asyncio.get_event_loop() anchor_strategy = Anchor(loop) loop.run_until_complete(anchor_strategy.run(params))
async def socket_handler(self, request): ws = aiohttp.web.WebSocketResponse() ok, protocol = ws.can_prepare(request) if not ok: return aiohttp.web.Response(text='Somthing went wrong') await ws.prepare(request) request.app['sockets'].add(ws) try: async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: try: req = json.loads(msg.data) if 'admin' in req: await self.cb(req) elif 'config' in req: log.info('Recieved new configuration: {}', req) await self.cb(req) except Exception as e: log.exception('Unexpected Error: {}', e) await ws.close() elif msg.type == aiohttp.WSMsgType.ERROR: log.info('Conn closed w/ exception: {}', ws.exception()) await ws.close() finally: request.app['sockets'].remove(ws) return ws
def apply_trade(self, order, trade, side): # Trade impacted one of our outstanding orders! log.info('{} [{}] - {}', TRADE_IMPACT, trade, side) self._session.on_order_fill(order, trade.qty) if order.remaining_qty == 0: self._session.notify_complete(order)
async def _log_orders(self): orders = await self._session.exch_orders() open_orders = "" for o in orders: open_orders = " " + str(o.price) + ", " + \ str(o.remaining_qty) + ", " + str(o.original_qty) + "|" log.info('Open Orders: {}', open_orders)
async def initialize_state(self, update): log.info("Initializing state: Cancelling outstanding orders...") # Cancel all outstanding ordes await self.trader.cancel_all() await self.init_balances() await self.init_pnl(update) await self.broadcast_config() log.info('Strategy Params: {}', to_json(StrategyConfig))
async def init_balances(self): # Get balances balance = await self.trader.get_balance() log.info('Initial Balance: {}', balance) StrategyConfig["last_update_time"] = datetime.now() StrategyConfig["initial_state"] = { "start_time": datetime.now(), "balances": balance }
async def init(self, loop, ip, port, instrument): self._app = aiohttp.web.Application(loop=loop) self._app['sockets'] = set() self._app.router.add_get('/ws', self.socket_handler) self._handler = self._app.make_handler() self._srv = await loop.create_server(self._handler, ip, port) self._session = aiohttp.ClientSession() log.info('Running web server at {}:{}', ip, port)
async def _dispatch_cancel_actions(self, to_cancel, open_orders_map): cancel_tasks = [] canceling_orders = "" for o in to_cancel: open_order = open_orders_map[round(o.price, 2)] if open_order.is_open: canceling_orders += " " + str(o.price) + ", " + str( o.qty) + "|" task = asyncio.ensure_future( self._trader.cancel_order(open_order)) cancel_tasks.append(task) await asyncio.gather(*cancel_tasks) if to_cancel: log.info('Cancelled Orders: {}', canceling_orders)
async def _dispatch_submit_actions(self, to_add, open_orders_map): submit_tasks = [] adding_orders = "" for o in to_add: adding_orders += " " + str(round(o.price, 2)) + \ ", " + str(round(o.qty, 2)) + "|" task = asyncio.ensure_future( self._trader.submit_order(side=o.side, price=round(o.price, 2), qty=round(o.qty, 2), ioc=False, quote=True)) submit_tasks.append(task) await asyncio.gather(*submit_tasks) if to_add: log.info('Added Orders: {}', adding_orders)
async def on_gap(self): # Need to manually update the state of every order in existance log.warn('Gapped! Need to request fill status of all orders') tasks = [] for open_order in self._session.open_orders: task = asyncio.ensure_future( self._session.get_fill(open_order.order_id)) tasks.append(task) order_fill_pairs = await asyncio.gather(*tasks) for pairs in order_fill_pairs: for pair in pairs: order = pair[0] fill = pair[1] log.info('Apply fill found after gap: [Order-{}], [Fill-{}]', order, fill) self._session.on_order_fill(order, make_qty(fill['size'])) if order.remaining_qty == 0: self._session.notify_complete(order)
async def poll_sub(self, sub, web_server): log.info('Starting Anchor Strategy') await asyncio.sleep(3) is_valid_book = False while not is_valid_book: update = await sub.fetch() if len(update.book.bids) > 0 and len(update.book.asks) > 0: await self.initialize_state(update) await self.strategy.on_parameters(StrategyConfig['parameters']) await self.strategy.on_market_data(update) is_valid_book = True else: await asyncio.sleep(1) while True: update = await sub.fetch() await self.strategy.on_market_data(update) # TODO: if we get traded against, we would want to # let the startegy take an action - poll at a faster rate # and check to see if anything happened, otherwise, yield control # at the configured interval await asyncio.sleep(StrategyConfig['parameters']['md_refresh'])
def _log_error(self, error_type, error, trigger): log.error(error) msg = {'error': str(error), 'trigger': trigger} log.info('Error Msg: [{}] {}', error_type, msg)
async def _log_balance(self): balance = await self.get_balance() log.info('Balances: base=avail:{}|hold:{}, quote=avail:{}|hold:{}', balance['base']['available'], balance['base']['hold'], balance['quote']['available'], balance['quote']['hold'])
async def _log_ack(self, msg_type, order): log.info('Submitted order for {}', str(order))