zoukankan      html  css  js  c++  java
  • BotVS数字货币现货交易类库

    以下是BotVS数字货币现货交易类库模板,使用Python2语言实现

    import types # 导入类型模块
    import time  # 导入时间模块
    import platform # 版本信息
    
    versionMainValue = None
    isFirstCheck = True
    
    # 判断数据类型
    def typeOfstr(str):
        if str == "list":
            if versionMainValue == 2:
                return types.ListType
            elif versionMainValue == 3:
                return list
        elif str == "int":
            if versionMainValue == 2:
                return types.IntType
            elif versionMainValue == 3:
                return int
        elif str == "float":
            if versionMainValue == 2:
                return types.FloatType
            elif versionMainValue == 3:
                return float
        else:
            Log("error , typeOfstr used false")
    
    # 检测当前系统Python版本
    def CheckVersion():
        global versionMainValue,isFirstCheck
        platformInfo = platform.python_version()
        if platformInfo[0] == '2':
            Log("您使用的托管者 python编译环境的python版本是",platformInfo)
            versionMainValue = 2
        elif platformInfo[0] == '3':
            Log("您使用的托管者 python编译环境的python版本是",platformInfo)
            versionMainValue = 3
        else:
            Log("其它版本")
        isFirstCheck = False
    
    # 取消所有未完成挂单,orderType指定要买单还是卖单,或者都包括
    def CancelPendingOrders(e, orderType = "") :
        while True:
            orders = e.GetOrders()      #获取所有未成交的挂单
            LogStatus("orders:",orders,time.time()) 
            if(type(orders) != typeOfstr("list")):  #异常处理: orders 类型不为list,表示获取数据出错。
                Sleep(RetryDelay)
                continue
            processed = 0               # 计数器,统计有多少个挂单
            for j in range(len(orders)):        # 循环处理挂单,此处可以优化循环使用 for order in orders:
                if (type(orderType) == typeOfstr("int") and orders[j].Type != orderType):   #不是指定的订单类型不处理
                    continue
                e.CancelOrder(orders[j].Id,orders[j])   #取消指定订单
                processed += 1              #计数器加1
                if (j < (len(orders) - 1)): #每处理一次,休息一下
                    Sleep(RetryDelay)
            if(processed == 0):
                break
    
    # 获取账号信息 waitFrozen 是否等待冻结
    def GetAccount(e, waitFrozen = False):
        account = null
        alreadyAlert = False            #用于标记是否已提醒过
        while True:
            account = _C(e.GetAccount)  #调用API 获取当前账户信息
            if(not waitFrozen or (account.FrozenStocks < e.GetMinStock() and account.FrozenBalance < 0.01)):#不等待冻结或冻结数量小于最小交易量,直接中断循环
                break
            if(not alreadyAlert):       #否则,并在没有提醒过时,则返回冻结信息
                alreadyAlert = True
                Log("发现账户有冻结的钱或币",account)
            Sleep(RetryDelay)           #[JS原注释]注意 : 如果有冻结的钱 或者 币 有可能一直卡在此处。
        return account
    
    # 取消 除参数指定的orderId 以外 的所有未成交的挂单。
    def StripOrders(e,orderId = null):
        order = null
        while True:
            dropped = 0                 # 统计取消订单数
            orders = _C(e.GetOrders)    # 获取所有订单
            for i in range(len(orders)):
                if(orders[i].Id == orderId):    #指定订单不处理
                    order = orders[i]
                else:                           #其他订单都处理
                    extra = ""
                    if(orders[i].DealAmount > 0):   #已经成交量
                        extra = "成交:" + str(orders[i].DealAmount)
                    else:
                        extra = "未成交"
                    e.CancelOrder(orders[i].Id, "买单" if orders[i].Type == ORDER_TYPE_BUY else "卖单",extra)
                    dropped += 1
            if(dropped == 0):
                break
            Sleep(RetryDelay)
        return order
    
    
    # 交易函数,e:交易所对象, tradeType:交易类型 , tradeAmount:交易数量, mode:模式, slidePrice:滑价, maxAmount:单次最大交易量, maxSpace: 最大挂单距离, retryDelay: 重试时间。
    # mode = 0 : direct buy吃单, 1 : buy as buy1 挂单
    def Trade(e, tradeType, tradeAmount, mode, slidePrice, maxAmount, maxSpace, retryDelay):
        initAccount = GetAccount(e,True)        # 初始时 获取账户信息。
        nowAccount = initAccount                # 用于保存当前账户信息的变量,初始化为 initAccount
        orderId = null                          # 声明一个用于保存 订单ID 的变量
        prePrice = 0.0                          # 上一次的价格
        dealAmount = 0.0                        # 已经处理过的(成交过的) 交易数量
        diffMoney = 0.0                         # 账户 钱之差
        isFirst = True                          # 是否是 第一次的循环的 标记
        tradeFunc = e.Buy if tradeType == ORDER_TYPE_BUY else e.Sell    # 根据参数 tradeType 确定 调用API  Buy 还是 Sell 。让 tradeFunc 引用相应的API接口。 
        isBuy = (tradeType == ORDER_TYPE_BUY)   # 是否是 Buy的标记, 用 tradeFunc == ORDER_TYPEBUY 表达式的布尔值 初始化。
        while True:
            ticker = _C(e.GetTicker)            # 获取当前行情数据 _C 重试函数
            tradePrice = 0.0                    # 初始交易价格 0
            if(isBuy):                          # 如果是 买入操作 
                # 吃单或 挂单 价,再加滑价,来成交, (ticker.Buy + slidePrice) 为买一价+滑价,可能达不到卖1价,所以算挂单,但比挂1 高出一点,可能优先成交
                tradePrice = _N((ticker.Sell if mode == 0 else ticker.Buy) + slidePrice,4)  
            else:
                tradePrice = _N((ticker.Buy if mode == 0 else ticker.Sell) - slidePrice,4)
            if(not orderId):
                if(isFirst):
                    isFirst = False
                else:
                    nowAccount = GetAccount(e,True)
                doAmount = 0.0;
                if(isBuy):      #  如果是 买入操作 
                    diffMoney = _N(initAccount.Balance - nowAccount.Balance,4)  # 每次记录 ,用于最后计算 成交均价
                    dealAmount = _N(nowAccount.Stocks - initAccount.Stocks,4)   # 实际已经 处理完成的量(成交)
                    doAmount = min(maxAmount,tradeAmount - dealAmount,_N((nowAccount.Balance - 10) / tradePrice,4)) # 根据几个待选 值取最小的。
                else:           #  处理 卖出的操作
                    diffMoney = _N(nowAccount.Balance - initAccount.Balance,4)
                    dealAmount = _N(initAccount.Stocks - nowAccount.Stocks,4)
                    doAmount = min(maxAmount,tradeAmount - dealAmount,nowAccount.Stocks)
                if(doAmount < e.GetMinStock()):  #要处理的量 小于 平台的最小成交量 ,即为交易完成,跳出循环
                    break
                prePrice = tradePrice           # 把本次循环计算出来的 交易价格 缓存到 prePrice 变量
                orderId = tradeFunc(tradePrice, doAmount, ticker)    # 下单 ,附带输出  ticker 数据
                if(not orderId):                # 如果 orderId 为 null ,取消所有挂单
                    CancelPendingOrders(e,tradeType)
            else:           # orderId 存在了
                if(mode == 0 or (abs(tradePrice - prePrice) > maxSpace)):   # 如果是挂单模式,超出挂单最大失效距离, 则把orderId赋值 为 null 。
                    orderId = null
                order = StripOrders(e,orderId)  # 取消 除orderId 以外的所有挂单,并返回 orderId 的 order信息
                if(not order):
                    orderId = null
            Sleep(retryDelay)
        
        #处理量 小于等于 0 , 即 无法操作,  交易失败,返回 null     
        if(dealAmount <= 0):
            Log("交易失败--TradeType:","buy" if tradeType == ORDER_TYPE_BUY else "sell","  ,diffMoney:",diffMoney,"  ,dealAmount",dealAmount,"  ,doAmount",doAmount)
            return null
        
        # 返回 成功的交易信息,  成交均价、  成交数量。
        ret = {'price': _N(diffMoney/dealAmount,4),'amount':dealAmount}
        return ret
    
    # 导出函数  处理买入操作
    def _Buy(e = exchange,amount = 0):
        if isFirstCheck:
            CheckVersion()
        if (type(e) == typeOfstr("int") or type(e) == typeOfstr("float")):
            amount = e
            e = exchange
        return Trade(e,ORDER_TYPE_BUY,amount,OpMode,SlidePrice,MaxAmount,MaxSpace,RetryDelay)
    
    # 导出函数   处理卖出操作
    def _Sell(e = exchange,amount = 0):
        if isFirstCheck:
            CheckVersion()
        if (type(e) == typeOfstr("int") or type(e) == typeOfstr("float")):
            amount = e
            e = exchange
        return Trade(e,ORDER_TYPE_SELL,amount,OpMode,SlidePrice,MaxAmount,MaxSpace,RetryDelay)
    
    # 导出函数  用于 取消所有未完成 挂单
    def _CancelPendingOrders(e = exchange,orderType = ""):
        if isFirstCheck:
            CheckVersion()
        return CancelPendingOrders(e,orderType)
    
    # 用于 获取当前账户信息  区别于  GetAccount(e, waitFrozen)
    def _GetAccount(e = exchange):
        if isFirstCheck:
            CheckVersion()
        return _C(e.GetAccount)
    
    _MACalcMethod = [TA.EMA,TA.MA][MAType]  #均线指标设置
    Interval = 200
    # 均线交叉 函数,用于 判断 均线交叉 返回上穿的周期数. 正数为上穿周数, 负数表示下穿的周数, 0指当前价格一样
    def Cross(a,b):                         
        if isFirstCheck:
            CheckVersion()
        crossNum = 0            # 交叉周期计数
        arr1 = []               # 声明数组 arr1  用来 接收 指标数据 (数组结构)
        arr2 = []               # 判断 参数 传入的是 周期数 还是 计算好的 指标数据(数组)
        if type(a) == typeOfstr("list") and type(b) == typeOfstr("list"):   # 如果是 数组 就把 a 参数(即指标数组)赋值给 arr1 
            arr1 = a
            arr2 = b
        else:                   # 如果传入的  a,b 不是 数组 ,是 周期数  执行一下。
            records = null  
            while True:
                records = exchange.GetRecords()     # 调用  GetRecords  获取K线数据
                if records and len(records) > a and len(records) > b:    #判断 如果 records 获取到数据 并且 records K线数据 的 bar 个数(即 records 这个数组的长度) 大于 参数 周期数  a ,b  ,代表符合计算指标的要求。(bar 个数不够 是计算不出指标数据的)
                    break
                Sleep(Interval)
            arr1 = _MACalcMethod(records,a)     # 根据界面参数 MAType 的设置  引用 指标的函数名,在这里 传入K线数据,指标参数 周期数a  , 去计算 指标数据,指标数据返回给 arr1 
            arr2 = _MACalcMethod(records,b)     # MAType 是一个索引 ,根据 你界面上的设置 设置为相应的 索引 0 ~ n 自上而下, 这个索引 又确定了 [TA.EMA, TA.MA, talib.KAMA] 这个数组种  哪个  函数引用 赋值给  _MACalcMethod ,从而确定调用哪种 指标计算函数。
        if len(arr1) != len(arr2):              # 相同K线 计算出的 指标数据 长度 应当是一样的,不一样则异常
            raise Exception("array length not equal")
        for i in range(len(arr1) - 1,-1,-1):    # 从指标数据  数组 自后向前  遍历数组
            # 读取到任何 指标数据不为数值类型的时候就跳出,即 指标数据 由于计算周期不同,有数据 为null 了,无法比较 ,所以 只用 arr1 arr2 都是有效值的数据。
            if (type(arr1[i]) != typeOfstr("int") and type(arr1[i]) != typeOfstr("float")) or (type(arr2[i]) != typeOfstr("int") and type(arr2[i]) != typeOfstr("float")):
                break
            # 此处 比较难以理解,由于crossNum 初始为0 , 不会触发一下 if 内的代码, arr1[i] 、arr2[i] 比较是 自后向前比较的, 即从离当前时间最近的 bar 的指标开始对比的, arr1[i] < arr2[i] 快线小于慢线,所以 在初始 crossNum 为0 的时候 ,快线小于慢线的 周期数 会持续记录在crossNum中, 直到 出现 arr1[i] > arr2[i] 的时候,此刻即 快线  慢线相交(这个时候break, crossNum 就是交叉后的周期数,最直观的就是 自己 模拟2组快慢线 数据数组,带入此处函数 根据逻辑 走一遍就明白了。)
            if arr1[i] < arr2[i] :
                if crossNum > 0 :
                    break
                crossNum -= 1
            elif arr1[i] > arr2[i] :
                if crossNum < 0 :
                    break
                crossNum += 1
            else:
                break
        return crossNum
    
    
    # 导出函数
    ext.Buy = _Buy
    ext.Sell = _Sell
    ext.CancelPendingOrders = _CancelPendingOrders
    ext.GetAccount = _GetAccount
    ext.Cross = Cross
    
    # 测试
    def main():
        ret = ext.Buy(0.2)
        exchange.Sell(4500,1)
        Sleep(10 * 1000)
        ext.CancelPendingOrders()
        Log("ret:",ret)
        avgprice = ret['price']
        dealamount = ret['amount']
        Log("avgprice:",avgprice,"  dealamount:",dealamount)

    模板参数

  • 相关阅读:
    Hard 随机洗牌函数 @CareerCup
    Hard 随机选择subset @CareerCup
    Hard 计算0到n之间2的个数 @CareerCup
    Django admin进阶
    hdu 5630 Rikka with Chess
    PHP 表单验证
    PHP 表单验证
    PHP 表单验证
    PHP 表单验证
    PHP 表单处理
  • 原文地址:https://www.cnblogs.com/bitquant/p/botvs-digiccy-spot-classlib.html
Copyright © 2011-2022 走看看