Python版冰山委託策略

本期文章,帶來兩個移植的經典策略:冰山委託(買入/賣出)。策略移植自發明者量化交易平臺經典策略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模擬交易所測試:
買入

賣出

策略邏輯並不複雜,策略執行時,根據策略參數、當時行情價格,動態的掛單、撤單。當交易金額/幣數達到、接近參數設置數量時,策略停止。策略代碼非常簡單,適合初學。有興趣的同學可以加以改造,設計成適合自己交易方式的策略。
策略爲教學性質,實盤慎用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章