def __WorkThread(): """ 数据下载线程 如果换成别的交易所,需要改这个函数里的下载那一行代码 """ global __exceptionTime,__exceptionCount, __terminated while(True): if __terminated: break try: startTime = time.time() depthData = HuobiServices.get_depth(__symbol,'step0') endTime = time.time() usedTime = endTime - startTime waitTime = 1 - usedTime - 0.1 if depthData != None and depthData['status'] == 'ok': bid1 = depthData['tick']['bids'][0][0] ask1 = depthData['tick']['asks'][0][0] __ParseData(bid1,ask1) if waitTime > 0: time.sleep(waitTime) except Exception as e: if __exceptionTime < 0: __exceptionTime = int(time.time()) __exceptionCount += 1 Log.Print("Download Data Exception: ",str(e)) Log.Info(__logFile,"Download Data Exception: " + str(e)) time.sleep(1) finally: if __exceptionTime > 0: currTime = int(time.time()) diffSeconds = currTime - __exceptionTime if diffSeconds >= 60: #print("Exceptioin Count in 1Min:",__exceptionCount) Log.Info(__logFile,"Exception Count in 1Min: {}".format(__exceptionCount)) if __exceptionCount > 10: Log.Print("more than 15 times Exception in 1Min, Clear Data") Log.Info(__logFile,"more than 15 times Exception in 1Min, Clear Data") __InitData() __exceptionTime = currTime __exceptionCount = 0 logStr = "!!!Terminated DataDownloader Stoped!" Log.Print(logStr) Log.Info(Const.logFile,logStr)
def LockHold(self): """ 要卖的时候,本地调用此方法锁定一个持有 """ if self.state != 'hold': logStr = "HM - ##### FAILD! hold lock faild! " + self.__str__() Log.Print(logStr) Log.Info(Const.logFile,logStr) return False logStr = "HM - SUCCESS! hold lock successful! " + self.__str__() Log.Print(logStr) Log.Info(Const.logFile,logStr) self.state = 'lock' return True
def SendBuy(operationId, price, amount, cost): """ 直接在主线程中下买单,最多尝试2次 买入下单 operationId: 操作Id price: 买入价格 amount: 买入数量 cost: 买入总花费 """ global __tradeOperations for x in range(2): orderSended = False try: #orderData = HuobiServices.send_order(amount,'api','btcusdt','buy-limit',price) orderData = __DEBUG_ConstructTradeResult() status = orderData['status'] orderId = orderData['data'] if status == 'ok': orderSended = True buyOperation = TradeOperation(1, price, amount, operationId, orderId, cost) __tradeOperations.append(buyOperation) SaveTradeOperations() logStr = "OM - SUCCESS! Send Buy Order OK! operationId:{} price:{} amount:{} cost:{} orderId:{}".format( operationId, price, amount, cost, orderId) Log.Print(logStr) Log.Info(Const.logFile, logStr) return else: logStr = "OM - ##### FAILD! Send Buy Order FAILD! operationId:{} price:{} amount:{} rawJson:{}".format( operationId, price, amount, orderData) Log.Print(logStr) Log.Info(Const.logFile, logStr) except Exception as e: logStr = "OM - ##### EXCEPTION! Send Buy Order Exception! operationId:{} price:{} amount:{} Exception:{}".format( operationId, price, amount, e) Log.Print(logStr) Log.Info(Const.logFile, logStr) if orderSended == True: logStr = "OM - #### Buy FATAL ERROR!!!!!" Log.Print(logStr) Log.Info(Const.logFile, logStr) time.sleep(1) #走到这里,说明下买单失败,资金回滚 BalanceManage.BuyFallback(cost)
def SendSell(operationId, price, amount, buyCost): """ 卖出持有 operationId: 操作Id price: 卖出价格 amount: 卖出数量 buyCost: 购买的时候花了多少钱,用于计算收益 """ global __tradeOperations for x in range(2): orderSended = False try: #orderData = HuobiServices.send_order(amount,'api','btcusdt','sell-limit',price) orderData = __DEBUG_ConstructTradeResult() status = orderData['status'] orderId = orderData['data'] if status == 'ok': orderSended = True sellOperation = TradeOperation(0, price, amount, operationId, orderId, buyCost) __tradeOperations.append(sellOperation) SaveTradeOperations() logStr = "OM - SUCCESS! Send Sell Order OK! operationId:{} price:{} amount:{} cost:{} orderId:{}".format( operationId, price, amount, buyCost, orderId) Log.Print(logStr) Log.Info(Const.logFile, logStr) return else: logStr = "OM - ##### FAILD! Send Sell Order FAILD! operationId:{} price:{} amount:{} rawJson:{}".format( operationId, price, amount, orderData) Log.Print(logStr) Log.Info(Const.logFile, logStr) except Exception as e: logStr = "OM - ##### EXCEPTION! Send Sell Order Exception! operationId:{} price:{} amount:{} Exception:{}".format( operationId, price, amount, e) Log.Print(logStr) Log.Info(Const.logFile, logStr) if orderSended == True: logStr = "OM - #### Sell FATAL ERROR!!!!!" Log.Print(logStr) Log.Info(Const.logFile, logStr) sys.exit() time.sleep(1) # 因为一些原因,卖出失败了,所以要回滚持有 print("Ready Fallback ", operationId) HoldManager.FallbackHold(operationId)
def InitSystem(): """ 加载密钥,初始化交易所服务 获取Account id,赋值到交易所服务 """ configFile = "Config.json" try: configJsonStr = IOUtil.ReadTextFromFile(configFile) configData = json.loads(configJsonStr) access_key = configData['access_key'] secret_key = configData['secret_key'] HuobiServices.init_key(access_key, secret_key) accounts = HuobiServices.get_accounts() account_id = accounts['data'][0]['id'] HuobiServices.init_account(account_id) HuobiServices.init_symbols() except Exception as e: logStr = "Fatal Error: Init System Faild!\n Exception:{}".format(e) Log.Print(logStr) Log.Info(Const.logFile, logStr) sys.exit()
def Start(): t = threading.Thread(target=__WorkThread) t.setDaemon(True) t.start() logStr = "DataDownloader Started!" Log.Print(logStr) Log.Info(Const.logFile,logStr)
def Buy(price): """ 购买:根据价格和购买单位计算出需要花费多少 quote,把 quote 从原始资金拿到冻结资金中 注意:这里的价格是已经加了0.3 usdt 后的价格 """ global __totalQuote, __tradePart, __quoteBalance, __frozeQuoteBalance # 计算每次买入多少 usdt 的 btc costQuote = MathUtil.GetPrecision(__totalQuote / __tradePart, 2) if __quoteBalance > costQuote: # 资金足够,可以购买 __LogBalance("Before Buy Action") __quoteBalance -= costQuote __frozeQuoteBalance += costQuote # 计算要花费的 usdt 按现在的价格能买多少 btc buyAmount = costQuote / price buyAmount = MathUtil.GetPrecision(buyAmount, 4) Log.Print("BM - Buy Info: price:{} costQuote:{} buyAmount:{}".format( price, costQuote, buyAmount)) Log.Info( Const.logFile, "BM - Buy Info: price:{} costQuote:{} buyAmount:{}".format( price, costQuote, buyAmount)) __SaveBalance() __LogBalance("After Buy Action") return costQuote, buyAmount # 返回以 costQuote usdt 买入 buyAmount 的 btc return -1, -1
def UnLockHold(self): """ 因为一些原因下单失败,需要回滚持有 """ logStr = "HM - UnLock Hold: " + self.__str__() Log.Print(logStr) Log.Info(Const.logFile,logStr) self.state = 'hold'
def __WorkThread_CheckTradeFillState(): """ 检查所有订单的成交状态 """ logStr = "OrderManager Started!" Log.Print(logStr) Log.Info(Const.logFile, logStr) global __tradeOperations, __terminated while (__terminated != True): tradeLen = len(__tradeOperations) for x in range(tradeLen - 1, -1, -1): trade = __tradeOperations[x] if trade.exchangerOrderId != '': try: #jsonResult = HuobiServices.order_info(trade.exchangerOrderId) if trade.tradeType == 1: jsonResult = __DEBUG_ConstructBuyFillResult( trade.tradePrice, trade.tradeAmount) else: jsonResult = __DEBUG_ConstructSellFillResult( trade.tradePrice, trade.tradeAmount) if jsonResult['status'] == 'ok': state = jsonResult['data']['state'] if state == 'filled': fieldAmount = jsonResult['data']['field-amount'] fieldCashAmount = jsonResult['data'][ 'field-cash-amount'] fieldFees = jsonResult['data']['field-fees'] logStr = "OM - Exchanger Order FILLED! operationId:{} fieldAmount:{} fieldCashAmount:{} field-fees:{}".format( trade.operationId, fieldAmount, fieldCashAmount, fieldFees) Log.Print(logStr) Log.Info(Const.logFile, logStr) OnTradeFilled(trade, fieldCashAmount) except Exception as e: logStr = "OM - ##### EXCEPTION! Check Order State Faild! operationId:{} Exception:{}".format( trade.operationId, e) Log.Print(logStr) Log.Info(Const.logFile, logStr) time.sleep(1) time.sleep(2) Log.Print("!!!Terminated OrderManager Stoped!") Log.Info(Const.logFile, "!!!Terminated OrderManager Stoped!")
def SellFilled(self,filledPrice,filledCash): """ 当卖单成交时,调用此方法进行最终的结算 """ self.sellFilledPrice = filledPrice gainedQuote = filledCash profit = gainedQuote - self.buyCost profit = MathUtil.GetPrecision(profit,4) if profit <= 0: logStr = "HM - ##### FATAL ERROR! You are lose Money: !!!! " + self.__str__ + " filledPrice:{} filledCash:{}".format(filledPrice,filledCash) Log.Print(logStr) Log.Info(Const.logFile,logStr) sys.exit() self.state = 'selled' self.profit = profit logStr = "HM - Cool! Sell Filled: buyPrice:{} buyCost:{} holdAmount:{} sellPrice:{} filledCash:{} profit:{}".format(self.buyPrice,self.buyCost,self.holdAmount,self.sellFilledPrice,filledCash,profit) Log.Print(logStr) Log.Info(Const.logFile,logStr)
def OnTradeFilled(tradeOperation, fieldCash): """ 当一个订单成交时,从操作列表中找到对应的交易索引,然后从交易列表中删除,保存数据 """ global __tradeOperations index = -1 for x in range(len(__tradeOperations)): trade = __tradeOperations[x] if trade.operationId == tradeOperation.operationId: index = x break if index >= 0: del __tradeOperations[index] SaveTradeOperations() if tradeOperation.tradeType == 1: # 处理买入订单成交 gainedBase = tradeOperation.tradeAmount * 0.997 gainedBase = MathUtil.GetPrecision(gainedBase, 4) logStr = "OM - Buy Order Filled: operationId:{} gainedBase:{}".format( tradeOperation.operationId, gainedBase) Log.Print(logStr) Log.Info(Const.logFile, logStr) HoldManager.BuyFilled(tradeOperation.operationId, tradeOperation.tradePrice, gainedBase, tradeOperation.cost, tradeOperation.exchangerOrderId) BalanceManager.BuyFilled(tradeOperation.cost, gainedBase) elif tradeOperation.tradeType == 0: # 处理卖出订单成交 # TODO: 这里要实际成交一单,查看一下最终收益和自己计算的收益是否一样 fieldCash = float(fieldCash) * 0.997 # 这里为避免float交易不精确,所以往少里算一点 profit = fieldCash - tradeOperation.cost logStr = "OM - Sell Order Filled: operationId:{} fieldCash:{} profit:{}".format( tradeOperation.operationId, fieldCash, profit) Log.Print(logStr) Log.Info(Const.logFile, logStr) HoldManager.SellFilled(tradeOperation.operationId, tradeOperation.exchangerOrderId, tradeOperation.tradePrice, fieldCash) BalanceManager.SellFilled(fieldCash, profit, tradeOperation.tradeAmount)
def __LogBalance(actionName): global __baseBalance, __quoteBalance, __frozeQuoteBalance, __totalProfit, __totalQuote Log.Print( "BM - {}: baseBalance:{} quoteBalance:{} frozeQuote:{} totalProfit:{} totalQuote:{}" .format(actionName, __baseBalance, __quoteBalance, __frozeQuoteBalance, __totalProfit, __totalQuote)) Log.Info( Const.logFile, "BM - {}: baseBalance:{} quoteBalance:{} frozeQuote:{} totalProfit:{} totalQuote:{}" .format(actionName, __baseBalance, __quoteBalance, __frozeQuoteBalance, __totalProfit, __totalQuote))
def HoldOnSelling(self,sellOrderId): """ 当卖单下单成功后,调用此方法设置状态 """ if self.state != 'lock': logStr = "HM - ##### ERROR! hold state error for Sell! " + self.__str__() Log.Print(logStr) Log.Info(Const.logFile,logStr) self.state = 'selling' self.sellOrderId = sellOrderId
def FallbackHold(operationId): """ 卖出因为一些原因下单失败,回滚持有 """ for hold in holds: if hold.operationId == operationId: hold.UnLockHold() logStr = "HM - ##### Fallback Hold: " + hold.__str__() Log.Print(logStr) Log.Info(Const.logFile,logStr) break SaveHoldsData()
def HoldOnSelling(operationId,sellOrderId): """ 一个持有,卖出下单成功 """ for hold in holds: if hold.operationId == operationId: hold.HoldOnSelling(sellOrderId) logStr = "HM - Hold On Selling: " + hold.__str__() Log.Print(logStr) Log.Info(Const.logFile,logStr) break SaveHoldsData()
def BuyFallback(costQuote): """ 购买回滚,把当时要花费的 quote 从冻结资金拿到原始资金 """ global __quoteBalance, __frozeQuoteBalance __LogBalance("Before Buy Fallback") Log.Print("BM - Buy Fallback Info: costQuote:{}".format(costQuote)) Log.Info(Const.logFile, "BM - Buy Fallback Info: costQuote:{}".format(costQuote)) __frozeQuoteBalance -= costQuote __quoteBalance += costQuote __SaveBalance() __LogBalance("After Buy Fallback")
def LoadTradeOperations(): global __tradeOperations if os.path.exists(Const.dataFile_orderManager): try: jsonStr = IOUtil.ReadTextFromFile(Const.dataFile_orderManager) __tradeOperations = json.loads( jsonStr, object_hook=__Json2TradeOperationObj) except Exception as e: logStr = "OM - ##### EXCEPTION! Load Trade Operations Faild! EXCEPTION:{}".format( e) Log.Print(logStr) Log.Info(Const.logFile, logStr) sys.exit()
def __LoadHoldsData(): """ 加载所有的持有数据 """ global holds if os.path.exists(__dataFile): try: jsonStr = IOUtil.ReadTextFromFile(__dataFile) holds = json.loads(jsonStr,object_hook=__HoldJson2Obj) except Exception as e: logStr = "HM - ##### EXCEPTION! Load Hold Buy data exception: {}".format(e) Log.Print(logStr) Log.Info(Const.logFile,logStr) sys.exit()
def SellFilled(operationId, sellOrderId, filledPrice, filledCash): """ 一个卖出成交了 """ for x in range(len(holds)): hold = holds[x] if hold.operationId == operationId: hold.SellFilled(filledPrice,filledCash) del holds[x] ArchiveHold(hold) logStr = "HM - Sell Filled: " + hold.__str__() Log.Print(logStr) Log.Info(Const.logFile,logStr) break SaveHoldsData()
def BuyFilled(costQuote, baseAmount): """ 买入成交,从冻结资金中减去当时的花费,然后把购买的 base 数量加到原始资金中 注意:传到这里的 baseAmount 是已经去掉手续费的了 """ global __frozeQuoteBalance, __baseBalance __LogBalance("Before Buy Filled") Log.Print("BM - Buy Filled Info: costQuote:{} filledAmount:{}".format( costQuote, baseAmount)) Log.Info( Const.logFile, "BM - Buy Filled Info: costQuote:{} filledAmount:{}".format( costQuote, baseAmount)) __frozeQuoteBalance -= costQuote __baseBalance += baseAmount __SaveBalance() __LogBalance("After Buy Filled")
def SellFilled(filledQuote, profit, selledAmount): """ 如果卖出成交了,则把获得的 quote 资金加到原始资金中 """ global __baseBalance, __quoteBalance, __totalQuote, __totalProfit __LogBalance("Before Sell Filled") Log.Print( "BM - Sell Filled Info: filledQuote:{} profit:{} selledAmount:{}". format(filledQuote, profit, selledAmount)) Log.Info( Const.logFile, "BM - Sell Filled Info: filledQuote:{} profit:{} selledAmount:{}". format(filledQuote, profit, selledAmount)) __baseBalance -= selledAmount __quoteBalance += filledQuote __totalProfit += profit __totalQuote += profit __SaveBalance() __LogBalance("After Sell Filled")
def SetProbe(price, probeType, lastTriggeredProbe=None): if probeType == 0: # 设置下降探针 if lastTriggeredProbe != None and lastTriggeredProbe.probeType == 0: lastProbeLevel = lastTriggeredProbe.probeLevel currProbeLevel = lastProbeLevel * 1.2 else: currProbeLevel = 150 p = Probe(probeType, price - currProbeLevel, currProbeLevel) else: # 布置上升探针 if lastTriggeredProbe != None and lastTriggeredProbe.probeType == 1: lastProbeLevel = lastTriggeredProbe.probeLevel currProbeLevel = lastProbeLevel * 1.1 else: currProbeLevel = 100 p = Probe(probeType, price + currProbeLevel, currProbeLevel) logStr = "Set Probe: probeType:{} price:{} probeLevel:{} probePrice:{}".format( probeType, price, currProbeLevel, p.probePrice) Log.Print(logStr) Log.Info(Const.logFile, logStr) return p
def __LoadBalance(): """ 加载资产数据,如果数据文件不存在,则初始化资产数据 """ global __baseBalance, __quoteBalance, __frozeQuoteBalance, __totalProfit, __totalQuote if os.path.exists(__balanceFile): try: jsonStr = IOUtil.ReadTextFromFile(__balanceFile) jsonData = json.loads(jsonStr) __baseBalance = jsonData['baseBalance'] __quoteBalance = jsonData['quoteBalance'] __frozeQuoteBalance = jsonData['frozeQuoteBalance'] __totalProfit = jsonData['totalProfit'] __totalQuote = jsonData['totalQuote'] except Exception as e: Log.Print("BM - ##### Fatal Error , can not load balance file! ", e) Log.Info( Const.logFile, "BM - ##### Fatal Error, Can not load balance file! " + str(e)) sys.exit() else: __SaveBalance()
def Terminated(): if os.path.exists("terminated"): return True return False declineProbe = None riseProbe = None if __name__ == '__main__': InitSystem() StartSystem() logStr = "All System Started!" Log.Print(logStr) Log.Info(Const.logFile, logStr) while (True): if Terminated(): break if DataDownloader.DataValid() and len(DataDownloader.realTimeBids) > 0: currBidPrice = DataDownloader.realTimeBids[-1] TryToSell(currBidPrice) currAskPrice = DataDownloader.realTimeAsks[-1] if declineProbe == None and riseProbe == None: declineProbe = SetProbe(currAskPrice, 0) riseProbe = SetProbe(currAskPrice, 1) else: if len(DataDownloader.realTimeAsks) < 60: time.sleep(0.5)