async def delete(request): userid = request.user algoname = request.match_info['algoname'] try: algo = await get_existing_algo(userid, algoname) except: return json_response(STATUS_ERR % ERRORS[ERR_INTERNAL_ERROR], status=500) if algo: try: async with aiosqlite.connect(get_main_db()) as db: await db.execute("delete from algos where userid = ? and algoname = ?", [userid, algoname]) await db.execute("delete from deployed_algos where userid = ? and algoname = ?", [userid, algoname]) await db.commit() try: async with aiosqlite.connect(get_backtest_db()) as db: await db.execute("delete from backtest_request where userid = ? and algoname = ?", [userid, algoname]) await db.commit() except: pass except: return json_response(STATUS_ERR % ERRORS[ERR_INTERNAL_ERROR], status=500) else: return json_response(STATUS_ERR % ERRORS[ERR_RESOURCE_NOT_FOUND], status=400) return web.Response(text="OK")
async def create(request): # get request parameter reqparams = await request.json() if type(reqparams) != dict: return json_response(STATUS_ERR % ERRORS[ERR_INCORRECT_REQUEST], status=400) userid = request.user algoname = reqparams['algo_name'] if 'algo_name' in reqparams else '' tradepair = reqparams['trade_pair'] if 'trade_pair' in reqparams else '' candlesize = reqparams['candle_size'] if 'candle_size' in reqparams else '' strategyname = reqparams['strategy_name'] if 'strategy_name' in reqparams else '' parameters = reqparams['strategy_parameters'] if 'strategy_parameters' in reqparams else '' if not (algoname and tradepair and candlesize and strategyname): return json_response(STATUS_ERR % ERRORS[ERR_INCORRECT_REQUEST], status=400) try: existing_algo = await get_existing_algo(userid, algoname) if existing_algo: return json_response(STATUS_ERR % ERRORS[ERR_RESOURCE_ALREADY_EXIST], status=400) async with aiosqlite.connect(get_main_db()) as db: await db.execute("insert into algos(userid, algoname, tradepair, candlesize, strategyname, parameters) " "values (?, ?, ?, ?, ?, ?)", [userid, algoname, tradepair, candlesize, strategyname, json.dumps(parameters)]) await db.commit() except: return json_response(STATUS_ERR % ERRORS[ERR_INTERNAL_ERROR], status=500) return json_response(STATUS_OK)
async def deployed_algo_trades(request): userid = request.user deployment_id = request.match_info['deployment_id'] try: deployed = await get_deployed_algo(userid, deployment_id) except: return json_response(STATUS_ERR % ERRORS[ERR_INTERNAL_ERROR], status=500) trades = [] try: async with aiosqlite.connect(get_main_db()) as db: async with db.execute("select ts, advice, sold_asset, sold_amount, bought_asset, bought_amount " "from trades where deployment_id = ?", [deployment_id]) as cursor: async for row in cursor: trades += [ { 'ts': row[0], 'advice': row[1], 'sold_asset': row[2], 'sold_amount': row[3], 'bought_asset': row[4], 'bought_amount': row[5], } ] except: return json_response(STATUS_ERR % ERRORS[ERR_INTERNAL_ERROR], status=500) return json_response(json.dumps(trades))
async def update_deployed_status(deployment_id, status): try: async with aiosqlite.connect(get_main_db()) as db: await db.execute( "update deployed_algos set status = ? where id = ?", [status, deployment_id]) await db.commit() logging.debug( 'Updated deployed algo with deployment_id = %s, status = %s' % (deployment_id, status)) except: logging.exception( 'Error occurred while deployment_id = %s, status = %s' % (deployment_id, status)) raise
async def get_deployed_algo(userid, deployment_id): try: async with aiosqlite.connect(get_main_db()) as db: async with db.execute("select id, algoname, amount, num_cycles, status from " "deployed_algos where userid = ? and id = ?", [userid, deployment_id]) as cursor: async for row in cursor: return { 'id': row[0], 'algo_name': row[1], 'amount': row[2], 'num_cycles': row[3], 'status': row[4], } except: raise return None
async def get_existing_algo(userid, algoname): try: async with aiosqlite.connect(get_main_db()) as db: async with db.execute("select algoname, tradepair, candlesize, strategyname, parameters from " "algos where userid = ? and algoname = ?", [userid, algoname]) as cursor: async for row in cursor: return { 'algo_name': row[0], 'trade_pair': row[1], 'candle_size': row[2], 'strategy_name': row[3], 'strategy_parameters': json.loads(row[4]), } except: raise return None
async def deployed_algo_list(request): userid = request.user deployed_list = [] try: async with aiosqlite.connect(get_main_db()) as db: async with db.execute("select id, algoname, amount, num_cycles, status " "from deployed_algos where userid = ?", [userid]) as cursor: async for row in cursor: deployed_list += [ { 'id': row[0], 'algo_name': row[1], 'amount': row[2], 'num_cycles': row[3], 'status': row[4], } ] except: return json_response(STATUS_ERR % ERRORS[ERR_INTERNAL_ERROR], status=500) return json_response(json.dumps(deployed_list))
async def algo_list(request): userid = request.user algolist = [] try: async with aiosqlite.connect(get_main_db()) as db: async with db.execute("select algoname, tradepair, candlesize, strategyname, parameters from " "algos where userid = ?", [userid]) as cursor: async for row in cursor: algolist += [ { 'algo_name': row[0], 'trade_pair': row[1], 'candle_size': row[2], 'strategy_name': row[3], 'strategy_parameters': json.loads(row[4]), } ] except: return json_response(STATUS_ERR % ERRORS[ERR_INTERNAL_ERROR], status=500) return json_response(json.dumps(algolist))
async def deploy(request): userid = request.user reqparams = await request.json() if type(reqparams) != dict: return json_response(STATUS_ERR % ERRORS[ERR_INCORRECT_REQUEST], status=400) algoname = reqparams['algo_name'] if 'algo_name' in reqparams else '' amount = reqparams['amount'] if 'amount' in reqparams else '' num_cycles = reqparams['num_cycles'] if 'num_cycles' in reqparams else '' if not (algoname and amount and num_cycles): return json_response(STATUS_ERR % ERRORS[ERR_INCORRECT_REQUEST], status=400) try: existing_algo = await get_existing_algo(userid, algoname) if not existing_algo: return json_response(STATUS_ERR % ERRORS[ERR_RESOURCE_NOT_FOUND], status=400) async with aiosqlite.connect(get_main_db()) as db: cursor = await db.execute("insert into deployed_algos(userid, algoname, amount, num_cycles, status) " "values (?, ?, ?, ?, ?)", [userid, algoname, amount, num_cycles, DeployedAlgo.STATUS_NEW]) await db.commit() deployment_id = cursor.lastrowid dreq = {'deploy_id': deployment_id} user_profile = UserProfile(userid, request.account, request.account_secret) deployment_details = DeployedAlgo(Algo.from_dict(existing_algo), deployment_id, amount, num_cycles) await request.app['engine_pipeline'].put((Engine.COMMAND_DEPLOY, user_profile, deployment_details)) except: logging.exception('Exception occurred while processing deploy request') return json_response(STATUS_ERR % ERRORS[ERR_INTERNAL_ERROR], status=500) return json_response(json.dumps(dreq))
def execute_trade(trading_config, user_profile, deployment_id, trade_pair, advice, amount, num_cycles): asset_pairs = trade_pair.split('_') base_asset = get_asset(asset_pairs[0], asset_pairs[1]) counter_asset = get_asset(asset_pairs[2], asset_pairs[3]) logging.debug('Executing trade for did=%s for trade_pair=%s' % (deployment_id, trade_pair)) tcontext = get_trade_context(deployment_id) while True: if tcontext: lock = tcontext['lock'] lock.acquire() try: last_advice = tcontext['last_advice'] first_advice = tcontext['first_advice'] current_cycles = tcontext['current_cycles'] buy_amount = tcontext['amount'] sell_amount = tcontext['sell_amount'] if current_cycles >= num_cycles: logging.info( 'Did = %s is completed the %s cycles. Stopping.' % (deployment_id, num_cycles)) return False, ALGO_DONE, None if last_advice == advice: logging.info( 'Got sequential %s order from did=%s. Ignoring recent advice.' % (advice, deployment_id)) return False, ALGO_CONT, None if first_advice != advice: current_cycles += 1 tcontext['last_advice'] = advice tcontext['current_cycles'] = current_cycles finally: lock.release() break else: if advice == TradeAdvice.SELL: logging.info( 'Sell order without first buy order from did=%s. Ignoring advice.' % advice) return False, ALGO_CONT, None tcontext = dict() tcontext['lock'] = Lock() tcontext['first_advice'] = advice tcontext['last_advice'] = advice tcontext['current_cycles'] = 0 tcontext['amount'] = buy_amount = amount tcontext['sell_amount'] = sell_amount = 0 last_context = add_trade_context(deployment_id, tcontext) if last_context: tcontext = last_context continue else: break account = user_profile.account signer = user_profile.account_secret trxid = None err = None if advice == TradeAdvice.BUY: sell_asset, buy_asset = base_asset, counter_asset if math.floor(buy_amount) == 0: logging.info( 'Algo %d trying to generate buy order without available asset %s' % (deployment_id, sell_asset)) return False, ALGO_ERROR, ('Ran out of fund for asset = %s' % format_asset(sell_asset)) book = stellar.orderbook(selling=base_asset, buying=counter_asset).fetch() if len(book.bids): # get current market price of the asset market_bid = book.bids[0] logging.debug( 'Executing trade for did=%s amount=%s, at market_price=%s [%s -> %s]' % (deployment_id, buy_amount, market_bid[1], sell_asset, buy_asset)) with stellar.new_transaction(account, signers=[signer]) as t: # buy counter asset buy exchanging base asset t.add_offer(buy_amount, sell_asset, buy_asset, market_bid[1]) if t.is_success(): trxid, _ = t.result() logging.debug('Trade executed for did = %s, trxid = %s' % (deployment_id, trxid)) else: err = str(t.errors()) logging.error('Trade execution failed for did = %s, err = %s' % (deployment_id, err)) elif advice == TradeAdvice.SELL: sell_asset, buy_asset = counter_asset, base_asset if math.floor(sell_amount) == 0: logging.info( 'Algo %d trying to generate buy order without available asset %s' % (deployment_id, sell_asset)) return False, ALGO_ERROR, ('Ran out of fund for asset = %s' % format_asset(sell_asset)) book = stellar.orderbook(selling=counter_asset, buying=base_asset).fetch() if len(book.bids): # get current market price of the asset market_bid = book.bids[0] logging.debug( 'Executing trade for did=%s amount=%s, at market_price=%s [%s -> %s]' % (deployment_id, sell_amount, market_bid[1], sell_asset, buy_asset)) with stellar.new_transaction(account, signers=[signer]) as t: # sell counter asset buy exchanging base asset t.add_offer(sell_amount, sell_asset, buy_asset, market_bid[1]) if t.is_success(): trxid, _ = t.result() logging.debug('Trade executed for did = %s, trxid = %s' % (deployment_id, trxid)) else: err = str(t.errors()) logging.error('Trade execution failed for did = %s, err = %s' % (deployment_id, err)) else: logging.error('Incorrect advice %s' % advice) return False, ALGO_ERROR, 'Incorrect advice %s' % advice # todo log the trade in database recoconciliation if not trxid: # todo log error return False, ALGO_ERROR, err try: offerid = stellar.transaction(trxid).effects().first().offer_id if offerid: # remove offer if it still exist offers = stellar.account(account).offers().fetch().records for offer in offers: if offer.offerid == offerid: logging.debug( 'Removing residue offer for did = %s, offerid = %s' % (deployment_id, offerid)) # ignore the error assuming offer got fulfilled (hence offer-not-found) # we will check the final bought/sold below with stellar.new_transaction(account, signers=[signer]) as t: t.remove_offer(offerid, sell_asset, buy_asset) total_sold = 0 total_bought = 0 effects = stellar.transaction(trxid).effects().fetch().records for effect in effects: if effect.type == 'trade' and effect.account == account: total_sold += float(effect.sold_amount) total_bought += float(effect.bought_amount) if advice == TradeAdvice.BUY: lock = tcontext['lock'] try: lock.acquire() tcontext['amount'] = buy_amount - total_sold tcontext['sell_amount'] = sell_amount + total_bought finally: lock.release() elif advice == TradeAdvice.SELL: lock = tcontext['lock'] try: lock.acquire() tcontext['amount'] = buy_amount + total_bought tcontext['sell_amount'] = sell_amount - total_sold finally: lock.release() ts = (datetime.datetime.utcnow() - EPOCH).total_seconds() with sqlite.connect(get_main_db()) as db: db.execute( "insert into trades" "(ts, deployment_id, advice, sold_asset, sold_amount, bought_asset, bought_amount)" " values (?, ?, ?, ?, ?, ?, ?)", [ ts, deployment_id, advice, format_asset(sell_asset), float(total_sold), format_asset(buy_asset), float(total_bought) ]) db.commit() except Exception as e: logging.exception('Exception occurred while processing trade advice') return False, ALGO_ERROR, ('Internal error %s' % str(e)) logging.info( 'Trade executed for did=%s, sold_asset=%s, sold_amount=%s, bought_asset=%s, bought_amount=%s' % (deployment_id, sell_asset, total_sold, buy_asset, total_bought)) return True, None, None