美文网首页
Python版冰山委托策略

Python版冰山委托策略

作者: 发明者量化 | 来源:发表于2020-03-19 15:33 被阅读0次

    本期文章,带来两个移植的经典策略:冰山委托(买入/卖出)。策略移植自发明者量化交易平台经典策略JavaScript版冰山委托,策略地址:https://www.fmz.com/square/s:%E5%86%B0%E5%B1%B1%E5%A7%94%E6%89%98/1

    引用JavaScript版本策略介绍:

    冰山委托指的是投资者在进行大额交易时,为避免对市场造成过大冲击,将大单委托自动拆为多笔委托,根据当前的最新买一/卖一价格和客户设定的价格策略自动进行小单委托,在上一笔委托被全部成交或最新价格明显偏离当前委托价时,自动重新进行委托。

    很多交易所的交易页面都自带冰山委托工具,有着丰富的功能,不过如果想根据自身需求,定制一些功能或者改动一些功能,就需要更加灵活的工具了。发明者量化交易平台很好的解决了这个问题。策略广场上Python策略不多,一些希望使用Python语言编写交易工具、策略的交易者需要参考范例。因此,就把经典的冰山委托策略移植为Python版。

    Python版冰山委托 - 买入 策略代码及注释

    import random  # 导入随机数库
    
    def CancelPendingOrders():     # CancelPendingOrders 函数作用是取消当前交易对所有挂单。
        while True:                # 循环检测,调用GetOrders 函数,检测当前挂单,如果orders 为空数组,即len(orders) 等于0,说明订单全部取消了,可以退出函数,调用return 退出。
            orders = _C(exchange.GetOrders)
            if len(orders) == 0 :
                return 
    
            for j in range(len(orders)):     # 遍历当前挂单数组,调用取消订单的函数CancelOrder,逐个取消挂单。
                exchange.CancelOrder(orders[j]["Id"])
                if j < len(orders) - 1:      # 除了最后一个订单,每次都执行Sleep 让程序等待一会儿,避免撤单过于频繁。
                    Sleep(Interval)
    
    LastBuyPrice = 0       # 设置一个全局变量,记录最近一次买入的价格。
    InitAccount = None     # 设置一个全局变量,记录初始账户资产信息。
    
    def dispatch():        # 冰山委托逻辑的主要函数
        global InitAccount, LastBuyPrice     # 引用全局变量
        account = None                       # 声明一个变量,记录实时获取的账户信息,用于对比计算。
        ticker = _C(exchange.GetTicker)      # 声明一个变量,记录最近行情。
        LogStatus(_D(), "ticker:", ticker)   # 在状态栏输出时间,最新行情
        if LastBuyPrice > 0:                 # 当LastBuyPrice大于0时,即已经委托开始时,执行if条件内代码。
            if len(_C(exchange.GetOrders)) > 0:    # 调用exchange.GetOrders 函数获取当前所有挂单,判断有挂单,执行if条件内代码。
                if ticker["Last"] > LastBuyPrice  and ((ticker["Last"] - LastBuyPrice) / LastBuyPrice) > (2 * (EntrustDepth / 100)):   # 检测偏离程度,如果触发该条件,执行if内代码,撤单。
                    Log("偏离过多, 最新成交价:", ticker["Last"], "委托价", LastBuyPrice)
                    CancelPendingOrders()
                else :
                    return True
            else :    # 如果没有挂单,证明订单完全成交了。
                account = _C(exchange.GetAccount)     # 获取当前账户资产信息。
                Log("买单完成, 累计花费:", _N(InitAccount["Balance"] - account["Balance"]), "平均买入价:", _N((InitAccount["Balance"] - account["Balance"]) / (account["Stocks"] - InitAccount["Stocks"])))  # 打印交易信息。
            LastBuyPrice = 0   # 重置 LastBuyPrice为0
    
        BuyPrice = _N(ticker["Buy"] * (1 - EntrustDepth / 100))   # 通过当前行情和参数,计算挂单价格。
        if BuyPrice > MaxBuyPrice:    # 判断是否超过参数设置的最大价格
            return True
    
        if not account:               # 如果 account 为 null ,执行if 语句内代码,重新获取当前资产信息,复制给account
            account = _C(exchange.GetAccount)
    
        if (InitAccount["Balance"] - account["Balance"]) >= TotalBuyNet:  # 判断买入所花费的总钱数,是不是超过参数设置。
            return False
    
        RandomAvgBuyOnce = (AvgBuyOnce * ((100.0 - FloatPoint) / 100.0)) + (((FloatPoint * 2) / 100.0) * AvgBuyOnce * random.random())   # 随机数 0~1
        UsedMoney = min(account["Balance"], RandomAvgBuyOnce, TotalBuyNet - (InitAccount["Balance"] - account["Balance"]))
    
        BuyAmount = _N(UsedMoney / BuyPrice)   # 计算买入数量
        if BuyAmount < MinStock:         # 判断买入数量是否小于 参数上最小买入量限制。
            return False 
        LastBuyPrice = BuyPrice          # 记录本次下单价格,赋值给LastBuyPrice
        exchange.Buy(BuyPrice, BuyAmount, "花费:¥", _N(UsedMoney), "上次成交价", ticker["Last"]) # 下单
        return True
    
    def main():
        global LoopInterval, InitAccount    # 引用 LoopInterval, InitAccount 全局变量
        CancelPendingOrders()               # 开始运行时,取消所有挂单
        InitAccount = _C(exchange.GetAccount)   # 初始记录 开始时的账户资产
        Log(InitAccount)                        # 打印初始账户信息
        if InitAccount["Balance"] < TotalBuyNet:    # 如果初始时资产不足,则抛出错误,停止程序
            raise Exception("账户余额不足")
        LoopInterval = max(LoopInterval, 1)      # 设置LoopInterval至少为1
        while dispatch():                        # 主要循环,不停调用 冰山委托逻辑函数 dispatch ,当dispatch函数 return false 时才停止循环。
            Sleep(LoopInterval * 1000)           # 每次循环都暂停一下,控制轮询频率。
        Log("委托全部完成", _C(exchange.GetAccount))   # 当循环执行跳出时,打印当前账户资产信息。
    
    

    Python版冰山委托 - 卖出

    可以尝试,读一下「Python版冰山委托 - 卖出」的代码,策略逻辑和买入的是一样的,只有略微差别。

    import random
    
    def CancelPendingOrders():
        while True:
            orders = _C(exchange.GetOrders)
            if len(orders) == 0:
                return
            
            for j in range(len(orders)):
                exchange.CancelOrder(orders[j]["Id"])
                if j < len(orders) - 1:
                    Sleep(Interval)
    
    LastSellPrice = 0
    InitAccount = None
    
    def dispatch():
        global LastSellPrice, InitAccount
        account = None
        ticker = _C(exchange.GetTicker)
        LogStatus(_D(), "ticker:", ticker)   
        if LastSellPrice > 0:
            if len(_C(exchange.GetOrders)) > 0:
                if ticker["Last"] < LastSellPrice and ((LastSellPrice - ticker["Last"]) / ticker["Last"]) > (2 * (EntrustDepth / 100)):
                    Log("偏离过多,最新成交价:", ticker["Last"], "委托价", LastSellPrice)
                    CancelPendingOrders()
                else :
                    return True
            else :
                account = _C(exchange.GetAccount)
                Log("买单完成,累计卖出:", _N(InitAccount["Stocks"] - account["Stocks"]), "平均卖出价:", _N((account["Balance"] - InitAccount["Balance"]) / (InitAccount["Stocks"] - account["Stocks"])))
                LastSellPrice = 0
    
        SellPrice = _N(ticker["Sell"] * (1 + EntrustDepth / 100))
        if SellPrice < MinSellPrice:
            return True
    
        if not account:
            account = _C(exchange.GetAccount)
    
        if (InitAccount["Stocks"] - account["Stocks"]) >= TotalSellStocks:
            return False 
    
        RandomAvgSellOnce = (AvgSellOnce * ((100.0 - FloatPoint) / 100.0)) + (((FloatPoint * 2) / 100.0) * AvgSellOnce * random.random())
        SellAmount = min(TotalSellStocks - (InitAccount["Stocks"] - account["Stocks"]), RandomAvgSellOnce)
        if SellAmount < MinStock:
            return False 
    
        LastSellPrice = SellPrice
        exchange.Sell(SellPrice, SellAmount, "上次成交价", ticker["Last"])
        return True
    
    def main():
        global InitAccount, LoopInterval
        CancelPendingOrders()
        InitAccount = _C(exchange.GetAccount)
        Log(InitAccount)
        if InitAccount["Stocks"] < TotalSellStocks:
            raise Exception("账户币数不足")
        LoopInterval = max(LoopInterval, 1)
        while dispatch():
            Sleep(LoopInterval)
        Log("委托全部完成", _C(exchange.GetAccount))
    
    

    策略运行

    使用wexApp模拟交易所测试:
    买入


    卖出


    策略逻辑并不复杂,策略执行时,根据策略参数、当时行情价格,动态的挂单、撤单。当交易金额/币数达到、接近参数设置数量时,策略停止。策略代码非常简单,适合初学。有兴趣的同学可以加以改造,设计成适合自己交易方式的策略。
    策略为教学性质,实盘慎用。

    相关文章

      网友评论

          本文标题:Python版冰山委托策略

          本文链接:https://www.haomeiwen.com/subject/oyskyhtx.html