def set_symbols_precision(self): symbols = self.hbapi.get_symbols() # 初始化 log.info('获取usdt交易对价格精度: ts: %s' % datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) symbols_pd = pd.DataFrame(data=list(symbols['data']), columns=[ 'base-currency', 'quote-currency', 'price-precision', 'amount-precision', 'symbol-partition', 'symbol' ]) symbols_pd.rename(columns={ 'base-currency': 'base_currency', 'quote-currency': 'quote_currency', 'price-precision': 'price_precision', 'amount-precision': 'amount_precision', 'symbol-partition': 'symbol_partition' }, inplace=True) symbol_price = { 'platform': 'huobi', 'data': json_util.loads(symbols_pd.to_json(orient='records')) } self.DB_CONN.get_collection('symbol_precision').replace_one( {'platform': 'huobi'}, symbol_price, True)
def set_rt_price_to_mongo(self): symbols_pd = self.get_symbols_precision() usdt_symbols = list( symbols_pd.loc[symbols_pd.quote_currency == 'usdt'].loc[ symbols_pd.symbol_partition == 'main']['symbol']) real_price_list = [] log.info('获取usdt交易对 实时价格存库,ts: %s' % datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) for symbol in usdt_symbols: if 'hb10' not in symbol: trade_detail = self.hbapi.get_trade(symbol) real_price = trade_detail['tick']['data'][0]['price'] real_price_list.append((symbol, real_price)) price_df = pd.DataFrame(data=real_price_list, columns=['symbol', 'rt_price']) symbol_price = { 'platform': 'huobi', 'ts': datetime.datetime.utcnow(), 'data': json_util.loads(price_df.to_json(orient='records')) } self.DB_CONN.get_collection('symbol_price').replace_one( {'platform': 'huobi'}, symbol_price, True)
def get_predict_sign(self, interval=30): log.info('尝试获取交易信号, ts: %s' % datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) signal = self.DB_CONN.get_collection('sign_detail').find_one( { "ts": { '$lt': datetime.datetime.utcnow(), '$gte': datetime.datetime.utcnow() - datetime.timedelta(minutes=interval) }, "deal": False }, {"data": 1}, sort=[('ts', -1)], limit=1) if signal is not None: log.info('获取到 交易信号, ts: %s' % datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) id = signal['_id'] self.DB_CONN.get_collection('sign_detail').find_one_and_update( {"_id": id}, {'$set': { 'deal': True }}) return signal['data'] else: return None
def set_base_trade_price(self): tickers = self.hbapi.get_market_ticker() log.info('获取基准价格: ts: %s' % datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) base_trade_list = [] symbol_set = set() for ticker in tickers['data']: if 'usdt' in ticker['symbol']: symbol = ticker['symbol'] symbol_kline = self.hbapi.get_kline(symbol, '60min', 24) if symbol_kline is not None and 'ok' in symbol_kline['status']: for tick in symbol_kline['data']: if time.localtime( tick['id']).tm_hour == 0 and time.localtime( tick['id']).tm_min == 0: # if time.localtime(tick['id']).tm_hour == 16 and time.localtime(tick['id']).tm_min == 0: close = tick['close'] if symbol not in symbol_set: base_trade_list.append((symbol, close)) symbol_set.add(symbol) # base_trade_list = [('eosusdt', 8.8), ('eth', 5.2), ('trx/usdt', 0.03)] symbols_pd = pd.DataFrame(data=base_trade_list, columns=['symbol', 'base_price']) symbol__base_price = { 'platform': 'huobi', 'data': json_util.loads(symbols_pd.to_json(orient='records')) } self.DB_CONN.get_collection('symbol_base_price').replace_one( {'platform': 'huobi'}, symbol__base_price, True)
def set_rt_account_holding(self, acct_id=ACCOUNT_ID): # 拿到所有持仓,更新余额到mongo,拿出不为0的持仓返回 log.info('获取账户实时持仓,acct_id: %s, ts: %s' % (acct_id, datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"))) holding = self.hbapi.get_balance(acct_id) loads = json_util.loads(json.dumps(holding)) db_res = self.DB_CONN.get_collection('account').replace_one( {'data.id': acct_id}, loads, True)
def set_currency_back_list(self): log.info('获取已交易币种并存库,acct_id: %s, ts: %s' % (self.ACCOUNT_ID, datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"))) ''' 拿到现有非usdt头寸,将头寸加入到backlist ''' hold_list = self.get_account_holding(self.ACCOUNT_ID) real_price_list = self.get_real_trade_price() hold_df = pd.DataFrame(data=hold_list, columns=['currency', 'type', 'balance']) real_df = pd.DataFrame(data=real_price_list, columns=['symbol', 'rt_price']) real_df['currency'] = real_df['symbol'].str.replace('usdt', '') account_currenncy_df = pd.merge(hold_df, real_df, how='left', on='currency') account_currenncy_df['rt_price'] = pd.to_numeric( account_currenncy_df['rt_price'], errors='coerce').fillna(1) account_currenncy_df['balance'] = pd.to_numeric( account_currenncy_df['balance'], errors='coerce').fillna(0) account_currenncy_df['eval_usdt'] = account_currenncy_df[ 'rt_price'] * account_currenncy_df['balance'] # hold_df = account_currenncy_df.query('eval_usdt > 1.0 and rt_price != 1.0 ') hold_df = account_currenncy_df.query('eval_usdt > 1.0') if len(hold_df) > 0: hold_list = self.get_currency_black_list() if hold_list is None: hold_set = set(hold_df['currency']) else: hold_set = set(hold_list).union(list(hold_df['currency'])) holds = '' for currency in hold_set: holds = holds + ',' + currency hold_symbol = { 'platform': 'huobi', 'ts': datetime.datetime.utcnow(), 'data': holds.replace(',', '', 1) } self.DB_CONN.get_collection('trade_black_list_today').replace_one( {'platform': 'huobi'}, hold_symbol, True)
def get_predict_sign2(self, interval=30): log.info('尝试获取交易信号, ts: %s' % datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) mongo_uri = 'mongodb://%s:%s@%s:%s' % ('cocola_2018', 'cocola_dmx~!`', '149.28.18.43', 27017) DB_COIN = MongoClient(mongo_uri, authSource='coin', authMechanism='SCRAM-SHA-1') DB_COIN_CONN = DB_COIN['coin'] # now = math.ceil((datetime.datetime.utcnow() + datetime.timedelta(hours=8)).timestamp()) now = math.ceil((datetime.datetime.utcnow()).timestamp()) now_before_interval = now - 120 signal = DB_COIN_CONN.get_collection('result_currency').find_one( { "ts": { '$lt': now, '$gte': now_before_interval }, "deal": False }, { "data": 1, "symbol": 1 }, sort=[('ts', -1)], limit=1) if signal is not None: log.info('获取到 交易信号, ts: %s' % datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) id = signal['_id'] DB_COIN_CONN.get_collection('result_currency').find_one_and_update( {"_id": id}, {'$set': { 'deal': True }}) DB_COIN.close() # 转换 tuple 格式 signal_tupe = self.signal_fmt(signal) return signal_tupe else: DB_COIN.close() return None
def signal_fmt(self, signal): data = signal['data'] symbol = signal['symbol'] # begin_ts = math.floor(signal['data']['begin_ts']/1000) # end_ts = math.floor(signal['data']['end_ts']/1000) updown = signal['data']['updown'] signal = {} signal_tuple = list() # 获取当前时间,如果当前时间小于end_ts,且updown是1,则返回 # if round(datetime.datetime.now().timestamp()) < end_ts and updown == 1: if updown == 1: signal['symbol'] = str(symbol).replace('usdt', '') signal['direction'] = updown # 判断当日该交易对 是否发生过交易 log.info(str(signal)) signal_tuple.append(signal) return signal_tuple else: return None
def robin_stop_loss(): ''' 1.获取账户头寸 2.遍历持仓头寸,判断是否止盈/止损 3.止盈/止损, 发起卖单 ''' acct_id = afttrade.ACCOUNT_ID hold_df = pretrade.get_account_trade_currency(acct_id) # 未冻结账户 trade_currency = hold_df.loc[(hold_df.balance > 0) & (hold_df.type == 'trade')] if len(trade_currency) == 0: log.info('持仓为空,暂停止盈止损,ts: %s' % datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")) afttrade.clear_records() # afttrade 清空所有数据 for i in range(0, len(trade_currency)): symbol = trade_currency.iloc[i]['currency'] + 'usdt' balance = trade_currency.iloc[i]['balance'] log.info('持有币种:%s, 数量:%s ,判断止盈止损, ts: %s' % (symbol, balance, datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"))) if afttrade.take_profit(symbol): # 止盈 log.warn('%s 触发 止盈 请求' % symbol) order_id = deal.sell_operate(symbol, balance) deal.solve_unfillex_order(order_id, 'sell') if afttrade.stop_losses(symbol): # 止损,卖出操作 log.warn('%s 触发 止损 请求' % symbol) order_id = deal.sell_operate(symbol, balance) deal.solve_unfillex_order(order_id, 'sell')
def is_global_env_fine(self): base_price_list = self.get_base_trade_price() real_price_list = self.get_real_trade_price() if len(real_price_list) != len(base_price_list): base_price_list = self.get_base_trade_price() real_price_list = self.get_real_trade_price() len_real = len(real_price_list) len_base = len(base_price_list) # if len_real >= len_base: base_pd = pd.DataFrame(data=base_price_list, columns=['symbol', 'base_price']) real_pd = pd.DataFrame(data=real_price_list, columns=['symbol', 'rt_price']) price_merge_pd = pd.merge(base_pd, real_pd, on='symbol') price_merge_pd['change'] = ( price_merge_pd['rt_price'] - price_merge_pd['base_price']) / price_merge_pd['base_price'] # 涨跌计数 up_change = len(price_merge_pd.loc[price_merge_pd.change >= 0.008]) down_change = len(price_merge_pd.loc[price_merge_pd.change <= 0.008]) if down_change / len(price_merge_pd) > 0.7: log.warn("大盘 usdt交易对%s对, %s涨%s跌,清仓" % (len_real, up_change, down_change)) return True, False # 清仓,交易 elif up_change > down_change: log.info("大盘 usdt交易对%s对, %s涨%s跌,涨多跌少,正常交易" % (len_real, up_change, down_change)) return False, True else: # todo 改为允许卖出方向的交易 log.info("大盘 usdt交易对%s对, %s涨%s跌,跌多涨少,暂停交易" % (len_real, up_change, down_change)) return False, False
def stop_losses(self, symbol): # 买入时价格 match_order = self.hbapi.orders_matchresults( symbol, types='buy-market,buy-limit,buy-ioc') if len(match_order['data']) == 0: log.info("近两月 %s 没有持仓,不需要止损,若有持仓,请手动" % symbol) return False match_price = float(match_order['data'][0]['price']) trade_detail = self.hbapi.get_trade(symbol) # 实时价格 real_price = trade_detail['tick']['data'][0]['price'] change = round((real_price - match_price) / match_price, 4) if change <= -0.02: log.warn("%s 买入价%s 现价%s,达到止损条件 " % (symbol, match_price, real_price)) self.DB_CONN.get_collection('takeprofit').delete_one( {'symbol': symbol}) return True return False
def generate_trade_plan(): ''' 拿到账号持仓和信号,做第一决策 ''' acct_id = pretrade.ACCOUNT_ID # 信号币种 # signs_tuple = pretrade.get_predict_sign(interval=2) signs_tuple = pretrade.get_predict_sign2(interval=2) log.info(signs_tuple) if signs_tuple is None: return # signs_tuple = list() # a = {"symbol": "neo", "direction": 1} # signs_tuple.append(a) # 拿到所有币种的价格/数量精度 precesion_pd = pretrade.get_symbols_precision() signs_data = [(d['symbol'], d['direction']) for d in signs_tuple] sign_pd = pd.DataFrame(data=signs_data, columns=['currency', 'direction']) # 持仓币种 hold_df = pretrade.get_account_trade_currency(acct_id) # 未冻结账户 trade_currency = hold_df.loc[(hold_df.balance > 0) & (hold_df.type == 'trade')] # 要保留的头寸 ['','',''] keep_holds = pd.merge(trade_currency, sign_pd.loc[sign_pd.direction == 1], how='inner', on='currency') # 要清仓的头寸 ['','',''] sell_holds = pd.merge(trade_currency, sign_pd.loc[sign_pd.direction == 0], how='inner', on='currency') # 要买入的头寸 ['','',''] buy_holds = pdtool.difference(sign_pd.loc[sign_pd.direction == 1], trade_currency, 'currency', 'currency') # 排除掉当日禁止交易的币种 base_blacklist = pretrade.get_currency_black_list() if base_blacklist is not None: blackpd = pd.DataFrame(data=base_blacklist, columns=['currency']) buy_holds = pdtool.difference(buy_holds, blackpd, 'currency', 'currency') # 合并 价格/数量 精度信息 buy_holds = pd.merge( buy_holds, precesion_pd.loc[precesion_pd.quote_currency == 'usdt'], how='inner', left_on='currency', right_on='base_currency') ''' 获取大盘信息,做第二决策 ''' (clear, continue_ex) = pretrade.is_global_env_fine() if clear: # 大盘跌,全部清仓变成usdt clear_df = hold_df.query('currency != "usdt"') ''' rt_price_list = pretrade.get_real_trade_price() rt_price_df = pd.DataFrame(data=rt_price_list, columns=['symbol', 'rt_price']) rt_price_df['currency'] = rt_price_df['symbol'].str.replace('usdt', '') rt_price_df.drop('symbol', axis=1, inplace=True) # 卖出总额usdt clear_df = pd.merge(clear_df, rt_price_df, how='inner', on='currency') clear_df['value'] = clear_df['balance'] * clear_df['rt_price'] # 排除卖出额在1美元以下的品种,交易所阻止交易 clear_df = clear_df[clear_df.value >= 1] ''' log.info('大盘整体下跌,开始清仓') # todo 未测试 insert_id = pretrade.set_tradeplan(None, None, clear_df) log.info('生成清仓计划成功,计划id是: %s,时间: %s' % (insert_id, datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S %f'))) continue_ex = True if continue_ex: ''' 算出交易资金,调整交易计划并入库 ''' rt_price_list = pretrade.get_real_trade_price() rt_price_df = pd.DataFrame(data=rt_price_list, columns=['symbol', 'rt_price']) rt_price_df['currency'] = rt_price_df['symbol'].str.replace('usdt', '') rt_price_df.drop('symbol', axis=1, inplace=True) # 卖出总额usdt sell_holds = pd.merge(sell_holds, rt_price_df, how='inner', on='currency') if len(sell_holds) != 0: sell_holds[ 'value'] = sell_holds['balance'] * sell_holds['rt_price'] # 排除卖出额在1美元以下的品种,交易所阻止交易 sell_holds = sell_holds[sell_holds.value >= 1] sell_value = sell_holds['value'].sum() else: sell_value = 0 # 持仓usdt sum_usdt, hold_usdt = pretrade.get_account_currency() # 买入总额等于 待买币种数 * 账户资金*1/100 sum_usdt 1/100 (滑点 + 手续费) available_total = sell_value + hold_usdt - sum_usdt / 100 consumed_total = (sum_usdt / 10) * len(buy_holds) # 算出买入币种的数量 buy_holds = pd.merge(buy_holds, rt_price_df, how='inner', on='currency') buy_holds['buy_sum'] = sum_usdt / 10 buy_holds['balance'] = round( buy_holds['buy_sum'] / buy_holds['rt_price'], 4) for i in range(0, len(buy_holds)): buy_holds.at[(i, 'balance')] = int(buy_holds.iloc[i].balance * pow( 10, buy_holds.iloc[i].amount_precision)) / pow( 10, buy_holds.iloc[i].amount_precision) if available_total > consumed_total: # 可以交易 # tradeplan 所在的记录,暂时不用 insert_id = pretrade.set_tradeplan(keep_holds, buy_holds, sell_holds) log.info( '生成交易计划成功,计划id是: %s,时间: %s' % (insert_id, datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S %f'))) else: # 资金不足,取出保留仓位中亏损的币种,将其加入到sell_holds # 算出差额多少,需要卖几个持仓币种 log.info('资金不足,重新规划仓位') sell_cnt = math.ceil( round((consumed_total - available_total) / sum_usdt, 2) * 10) if len(keep_holds) > 0: keep_holds['changerate'] = 1 keep_holds['rt_price'] = 0 keep_holds['symbol'] = 'usdt' for k in range(0, len(keep_holds)): currency = keep_holds.iloc[k]['currency'] amount = keep_holds.iloc[k]['balance'] symbol = currency + 'usdt' trade_detail = hbapi.get_trade(symbol) # 实时价格 real_price = trade_detail['tick']['data'][0]['price'] keep_holds.loc[k, 'rt_price'] = real_price keep_holds.loc[k, 'symbol'] = currency + 'usdt' # 买入时价格 match_order = hbapi.orders_matchresults( symbol, types='buy-market,buy-limit,buy-ioc') if len(match_order['data']) > 0: match_price = match_order['data'][0]['price'] keep_holds.loc[k, 'changerate'] = round( (real_price - float(match_price)) / float(match_price), 4) else: keep_holds.loc[k, 'changerate'] = 0 pre_clear_df = keep_holds.query( 'changerate < 0.1').sort_values( by='changerate', ascending=True).head(sell_cnt) keep_holds = pdtool.difference(keep_holds, pre_clear_df, 'currency', 'currency') sell_holds = sell_holds.append(pre_clear_df) insert_id = pretrade.set_tradeplan(keep_holds, buy_holds, sell_holds) log.info( '生成交易计划成功,计划id是: %s,时间: %s' % (insert_id, datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S %f'))) else: ''' 两次交易信号上涨,价格也上涨,属于独立行情币种,忽略大盘,单独策略 ''' pass
def take_profit(self, symbol): # 买入时价格 match_order = self.hbapi.orders_matchresults( symbol, types="buy-limit,buy-market,buy-ioc") if len(match_order['data']) == 0: log.info("近两月 %s 没有持仓,不需要止盈, 若有持仓,请手动" % symbol) return False match_price = match_order['data'][0]['price'] match_time = match_order['data'][0]['created-at'] # match_price = 0.0133 # match_time = 1494870000 # 实时价格 trade_detail = self.hbapi.get_trade(symbol) real_price = trade_detail['tick']['data'][0]['price'] real_time = trade_detail['tick']['data'][0]['ts'] rt_data = { 'rt_price': real_price, 'rt_time': int(real_time), 'created_at': int(match_time), 'price': match_price, 'is_hold': True } # 取出最大价格 max_price = self.DB_CONN.get_collection('takeprofit').find_one( {'symbol': symbol}, { 'max_price': 1, '_id': 0 }) if max_price is not None: if len(max_price) != 0 and real_price > float( max_price['max_price']): rt_data = { 'rt_price': real_price, 'rt_time': int(real_time), 'created_at': int(match_time), 'price': match_price, 'max_price': round(float(real_price), 4), 'max_price_time': int(real_time) } elif len(max_price) == 0: rt_data = { 'rt_price': real_price, 'rt_time': int(real_time), 'created_at': int(match_time), 'price': match_price, 'max_price': round(float(match_price), 4), 'max_price_time': int(match_time) } update_res = self.DB_CONN.get_collection( 'takeprofit').find_one_and_update( {'symbol': symbol}, {'$set': rt_data}, upsert=True, return_document=ReturnDocument.AFTER) # 最大值有值 且 最大值与现价 回撤是否大于5% if max_price is not None and len(max_price) != 0: max_price = update_res['max_price'] rt_price = update_res['rt_price'] rise_back_point = float(max_price) * 0.95 if rt_price < rise_back_point: log.warn("%s 买入价%s 最高价%s 现价%s,达到止盈条件 " % (symbol, match_price, max_price, real_price)) self.DB_CONN.get_collection('takeprofit').delete_one( {'symbol': symbol}) return True return False
def clear_records(self): res = self.DB_CONN.get_collection('takeprofit').delete_many( {'is_hold': True}) log.info('清空 各交易对-最高价状态记录')