def test_buy__order_cancel(): order_number = 1 def patched_configure_poloniex(): polo = mock.Mock() polo.returnCompleteBalances.return_value = { config.get_pair_first_symbol(_pair): { 'available': 100.0 }, config.get_pair_second_symbol(_pair): { 'available': 100.0 }, } polo.returnOpenOrders.return_value = [{ 'type': 'buy', 'orderNumber': order_number, 'rate': 1, 'amount': 1 }] polo.returnTradeHistory.return_value = [] # polo.moveOrder.return_value = [{'type': 'buy', 'orderNumber': order_number_3, 'rate': 1, 'amount': 1}] return polo patch1 = mock.patch('conf.config.DB_PATH', '.{}'.format(random.randint(10000, 90000))) patch2 = mock.patch('orders_engine_helpers.functions.configure_poloniex', patched_configure_poloniex) with patch1, patch2: from orders_engine_helpers import process_move_orders from conf import database_setup as db with db.session_scope() as session: session.add(db.Price( buy=200, sell=100, avg=150, pair=_pair, )) session.add( db.Transaction( id=order_number, ts=datetime.datetime.utcnow().timestamp() - config.DROP_BUY_ORDER_DELAY - 1, status=config.TransactionStatus.ON_STOP, type=config.TransactionType.BUY, amount=1, price=1, )) process_move_orders.move_orders(_pair) with db.session_scope() as session: transaction = session.query(db.Transaction).first() assert transaction.status == config.TransactionStatus.CANCELLED
def test_process_buy_true_prediction(): def patched_configure_poloniex(): polo = mock.Mock() polo.returnCompleteBalances.return_value = { config.get_pair_first_symbol(_pair): { 'available': 100.0 } } polo.buy.return_value = {'orderNumber': 777777} return polo patch1 = mock.patch('conf.config.DB_PATH', '.{}'.format(random.randint(10000, 90000))) patch2 = mock.patch('orders_engine_helpers.functions.configure_poloniex', patched_configure_poloniex) with patch1: with patch2: from orders_engine_helpers import process_buy from conf import database_setup as db with db.session_scope() as session: session.add( db.Transaction(pair=_pair, status=config.TransactionStatus.TO_ENQUEUE, ts=100)) session.add( db.Price(pair=_pair, buy=20, sell=10, avg=15, ts=100)) process_buy.process_buy(_pair)
def _move_buy_order(order_data, latest_order, pair): target_price = float( latest_order.sell) * config.ORDERBOOK_FORCER_MOVE_PERCENT try: with db.session_scope() as session: order_data_query = session.query(db.Transaction).filter( db.Transaction.id == (order_data.orderNumber)) sql_order_data = order_data_query.all() if not sql_order_data: return sql_order_data = sql_order_data[0] if sql_order_data.ts + config.DROP_BUY_ORDER_DELAY < datetime.datetime.utcnow( ).timestamp(): logging.info( "Cancelling order {} BY TIME".format(sql_order_data)) polo.cancelOrder(order_data.orderNumber) functions._update_status(order_data.orderNumber, config.TransactionStatus.CANCELLED) return logging.info('Trying to force order %s', sql_order_data.id) new_order = attrdict.AttrDict( polo.moveOrder(order_data.orderNumber, target_price)) logging.info('Forcing to target price success') order_data_query.update({ db.Transaction.price: target_price, db.Transaction.id: new_order.orderNumber }) logging.info('Updating db success') return True except Exception as ex: with db.session_scope() as session: session.add( db.Sensor(ts=int(time.time() * 1000), type=config.SensorType.ERROR, value=12)) logging.warn('Exception when forcing to target price', ex) return False
def test_sell__order_cancel(): order_number = 1 def patched_configure_poloniex(): polo = mock.Mock() polo.returnCompleteBalances.return_value = { config.get_pair_first_symbol(_pair): { 'available': 100.0 }, config.get_pair_second_symbol(_pair): { 'available': 100.0 }, } polo.returnOpenOrders.return_value = [{ 'type': 'sell', 'orderNumber': order_number }] polo.returnTradeHistory.return_value = [] return polo patch1 = mock.patch('conf.config.DB_PATH', '.{}'.format(random.randint(10000, 90000))) patch2 = mock.patch('orders_engine_helpers.functions.configure_poloniex', patched_configure_poloniex) with patch1, patch2: from orders_engine_helpers import process_sell from conf import database_setup as db with db.session_scope() as session: session.add( db.Transaction( id=order_number, ts=datetime.datetime.utcnow().timestamp() - config.STOP_TIME - 1, )) process_sell.process_sell(_pair) with db.session_scope() as session: tr = session.query(db.Transaction).first() assert tr.status == config.TransactionStatus.ON_STOP
def _move_sell_order(order_data, latest_order, pair): target_price = float( latest_order.buy) / config.ORDERBOOK_FORCER_MOVE_PERCENT try: with db.session_scope() as session: order_data_query = session.query(db.Transaction).filter( db.Transaction.id == (order_data.orderNumber)) sql_order_data = order_data_query.all() if not sql_order_data: return sql_order_data = sql_order_data[0] if sql_order_data.status != config.TransactionStatus.ON_STOP: logging.info("Order waits rate stop {}".format(sql_order_data)) return logging.info('Trying to force order %s', sql_order_data.id) new_order = attrdict.AttrDict( polo.moveOrder(order_data.orderNumber, target_price)) logging.info('Forcing to target price success') order_data_query.update({ db.Transaction.price: target_price, db.Transaction.id: new_order.orderNumber }) logging.info('Updating db success') return True except Exception as ex: with db.session_scope() as session: session.add( db.Sensor(ts=int(time.time() * 1000), type=config.SensorType.ERROR, value=11)) logging.warn('Exception when forcing to target price %s', ex) return False pass
def test_sell__make_order(): order_number = 1 trade_id = 1 amount = 50 def patched_configure_poloniex(): polo = mock.Mock() polo.returnCompleteBalances.return_value = { config.get_pair_first_symbol(_pair): { 'available': 100.0 }, config.get_pair_second_symbol(_pair): { 'available': 100.0 }, } polo.sell.return_value = {'type': 'sell', 'orderNumber': order_number} polo.returnOpenOrders.return_value = [] polo.returnTradeHistory.return_value = [{ 'globalTradeID': trade_id, 'amount': amount, 'type': 'buy', 'rate': 1 }] return polo patch1 = mock.patch('conf.config.DB_PATH', '.{}'.format(random.randint(10000, 90000))) patch2 = mock.patch('orders_engine_helpers.functions.configure_poloniex', patched_configure_poloniex) with patch1, patch2: from orders_engine_helpers import process_sell from conf import database_setup as db process_sell.process_sell(_pair) with db.session_scope() as session: transaction = session.query(db.Transaction).first() trade = session.query(db.Trade).first() assert transaction.status == config.TransactionStatus.ENQUEUED assert trade.id == trade_id assert transaction.amount == amount assert transaction.type == config.TransactionType.SELL assert transaction.id == order_number
def _get_latest_order(pair): with db.session_scope() as session: latest_order = session.query( db.Price).filter(db.Price.pair == pair).order_by( db.Price.id.desc()).limit(1).all()[0] return latest_order
def _update_status(transaction_id, status): with db.session_scope() as session: session.query( db.Transaction).filter(db.Transaction.id == transaction_id).update( {db.Transaction.status: status})
def prediction(): with db.session_scope() as session: data = session.query(db.Sensor.ts, db.Sensor.value).filter( db.Sensor.type == config.SensorType.PREDICTION).all() return json.dumps(data)
def _price(): with db.session_scope() as session: data = session.query(db.Sensor.ts, db.Sensor.value).filter( db.Sensor.type == config.SensorType.PRICE).all() return json.dumps(data)
def _engine_ping(): with db.session_scope() as session: data = session.query(db.Sensor.ts, db.Sensor.value).filter( db.Sensor.type == config.SensorType.ERROR).all() return json.dumps(data)
def test_sell__order_move(): order_number = 1 order_number2 = 2 sell_price = 100 buy_price = 200 def patched_configure_poloniex(): polo = mock.Mock() polo.returnCompleteBalances.return_value = { config.get_pair_first_symbol(_pair): { 'available': 100.0 }, config.get_pair_second_symbol(_pair): { 'available': 100.0 }, } polo.returnOpenOrders.return_value = [{ 'type': 'sell', 'orderNumber': order_number, 'rate': 1, 'amount': 1 }] polo.returnTradeHistory.return_value = [] polo.moveOrder.return_value = { 'type': 'sell', 'orderNumber': order_number2, 'rate': 1, 'amount': 1 } return polo patch1 = mock.patch('conf.config.DB_PATH', '.{}'.format(random.randint(10000, 90000))) patch2 = mock.patch('orders_engine_helpers.functions.configure_poloniex', patched_configure_poloniex) with patch1, patch2: from orders_engine_helpers import process_move_orders from conf import database_setup as db with db.session_scope() as session: session.add( db.Price( buy=buy_price, sell=sell_price, avg=None, pair=_pair, )) session.add( db.Transaction( id=order_number, ts=datetime.datetime.utcnow().timestamp() - config.DROP_BUY_ORDER_DELAY + 100, status=config.TransactionStatus.ON_STOP, type=config.TransactionType.SELL, amount=1, price=1, )) process_move_orders.move_orders(_pair) with db.session_scope() as session: transaction = session.query(db.Transaction).all() assert len(transaction) == 1 assert transaction[0].id == order_number2 assert transaction[ 0].price == buy_price / config.ORDERBOOK_FORCER_MOVE_PERCENT
import time import orders_engine_helpers from conf import config, database_setup as db from functions import telegram_log while True: try: for pair in config.PAIRS: logging.info('START PROCESS PAIR %s', pair) orders_engine_helpers.process_move_orders.move_orders(pair) orders_engine_helpers.process_sell.process_sell(pair) orders_engine_helpers.process_buy.process_buy(pair) logging.info('FINISH PROCESS PAIR %s', pair) with db.session_scope() as session: session.add( db.Sensor(ts=int(time.time() * 1000), type=config.SensorType.ERROR, value=0)) except Exception as ex: with db.session_scope() as session: session.add( db.Sensor(ts=int(time.time() * 1000), type=config.SensorType.ERROR, value=100)) telegram_log.online_log_important( 'FATAL IN ORDER ENGINE: {}'.format(ex)) raise
def process_buy(pair): logging.info('START BUY PAIR %s', pair) with db.session_scope() as session: prediction_query = session.query(db.Transaction) prediction_query = prediction_query.filter(db.Transaction.pair == pair) prediction_query = prediction_query.filter( db.Transaction.status == config.TransactionStatus.TO_ENQUEUE) to_enqueue = prediction_query.all() balance = attrdict.AttrDict( polo.returnCompleteBalances()[config.get_pair_first_symbol(pair)]) logging.info(balance) balance.available = float(balance.available) session.add( db.Sensor(ts=int(time.time()) * 1000, value=balance.available, type=config.SensorType.BALANCE)) if not to_enqueue: logging.info('STOP BUY PAIR %s, BUY SKIP: NO PREDICTION', pair) telegram_log.online_log( 'BUY: no prediction for pair {} - skip buy'.format(pair)) return None to_enqueue = to_enqueue[0] # deleting old predictions prediction_query.delete() latest_order = functions._get_latest_order(pair) target_price = latest_order.sell * config.ORDERBOOK_FORCER_MOVE_PERCENT amount = config.ONE_BET / target_price if amount < config.MINIMAL_AMOUNT or amount > balance.available: logging.info('STOP BUY PAIR %s, BUY FAIL: NOT ENOUGH BALANCE', pair) telegram_log.online_log( 'BUY: prediction is True but not enought balance for pair {} - skip buy' .format(pair)) return False order_data = polo.buy(pair, target_price, amount) order_data = attrdict.AttrDict(order_data) telegram_log.online_log('BUY: {} - success'.format(pair)) telegram_log.online_log_important('BUY: Order {}'.format(order_data)) session.add( db.Transaction( id=order_data.orderNumber, ts=to_enqueue.ts, type=config.TransactionType.BUY, pair=pair, status=config.TransactionStatus.ENQUEUED, amount=amount, price=target_price, )) logging.info('STOP BUY PAIR %s, BUY SUCCESS', pair) return True
def process_sell(pair): # add stop statuses logging.info('START SELL PAIR %s', pair) with db.session_scope() as session: pair_orders = polo.returnOpenOrders(currencyPair=pair) for order_data in pair_orders: order_data = attrdict.AttrDict(order_data) if order_data.type == 'buy': continue order_data_query = session.query(db.Transaction).filter( db.Transaction.id == (order_data.orderNumber)) sql_order_data = order_data_query.all() if not sql_order_data: continue sql_order_data = sql_order_data[0] if sql_order_data.ts + config.STOP_TIME < datetime.datetime.utcnow( ).timestamp(): functions._update_status(order_data.orderNumber, config.TransactionStatus.ON_STOP) # reseiving done buy trades & generating new sell transactions trades = polo.returnTradeHistory(currencyPair=pair) old_sell_trades_ids = [i[0] for i in session.query(db.Trade.id).all()] new_trades = list( map( attrdict.AttrDict, filter( lambda tr: (tr['globalTradeID'] not in old_sell_trades_ids and tr['type'] == 'buy'), trades))) balance = attrdict.AttrDict(polo.returnCompleteBalances()[ config.get_pair_second_symbol(pair)]).available balance = float(balance) next_sell_amount = 0.0 for trade in new_trades: logging.exception('processing new trade for selling: %s', trade) trade.amount = float(trade.amount) trade.rate = float(trade.rate) can_sell_amount = balance target_price = trade.rate * config.STOP_PERCENT sell_amount = min(trade.amount + next_sell_amount, can_sell_amount) if sell_amount < config.MINIMAL_AMOUNT: next_sell_amount = sell_amount logging.exception( 'sell amount < minimal amount, skipping trade: %s', trade) continue next_sell_amount = 0 try: order_data = attrdict.AttrDict( polo.sell(pair, target_price, sell_amount)) except Exception as ex: session.add( db.Sensor(ts=int(time.time() * 1000), type=config.SensorType.ERROR, value=10)) logging.info('exception while trying to sell order: %s %s', trade, ex) continue session.add( db.Transaction( id=order_data.orderNumber, ts=datetime.datetime.utcnow().timestamp(), type=config.TransactionType.SELL, pair=pair, status=config.TransactionStatus.ENQUEUED, amount=sell_amount, price=target_price, )) balance -= sell_amount session.add( db.Trade(id=trade.globalTradeID, ts=datetime.datetime.utcnow().timestamp(), type=config.TradeType.BUY, status=config.TradeStatus.PROCESSED)) logging.info('STOP SELL PAIR %s', pair)