avatar of 发明者量化-小小梦 发明者量化-小小梦
집중하다 사신
4
집중하다
1271
수행원

파이썬을 위한 간단한 그리드 전략

만든 날짜: 2020-01-04 14:28:04, 업데이트 날짜: 2024-12-15 16:03:28
comments   6
hits   5334

파이썬을 위한 간단한 그리드 전략

파이썬을 위한 간단한 그리드 전략

Strategy Square에는 Python 전략이 많지 않으므로, 그리드 전략의 Python 버전을 소개합니다. 전략의 원리는 매우 간단합니다. 일련의 그리드 노드가 가격 범위 내에서 고정된 가격 거리에 생성됩니다. 시장이 변하면 가격이 그리드 노드 가격 위치에 도달하면 매수 주문이 이루어집니다. 이 주문이 실행되면 보류 주문 가격과 이익 차이를 기준으로 포지션을 마감하기 위한 매도 주문이 이루어집니다. 설정된 가격 범위 내에서 가격 변동을 포착합니다.

그리드 전략의 위험을 설명할 필요는 없습니다. 모든 그리드 유형 전략은 가격이 특정 범위 내에서 변동할 것이라는 베팅입니다. 가격이 그리드 범위를 벗어나면 심각한 변동 손실이 발생할 수 있습니다. 따라서 이 전략을 작성하는 목적은 Python 전략 작성 아이디어나 프로그램 설계에 대한 참고 자료를 제공하는 것입니다. 이 전략은 학습 목적으로만 사용되며 실제 거래는 매우 위험할 수 있습니다.

전략 아이디어에 대한 설명은 전략 코드 주석에 직접 작성되어 있습니다.

전략 코드

'''backtest
start: 2019-07-01 00:00:00
end: 2020-01-03 00:00:00
period: 1m
exchanges: [{"eid":"OKEX","currency":"BTC_USDT"}]
'''

import json

# 参数
beginPrice = 5000   # 网格区间开始价格
endPrice = 8000     # 网格区间结束价格
distance = 20       # 每个网格节点的价格距离
pointProfit = 50    # 每个网格节点的利润差价
amount = 0.01       # 每个网格节点的挂单量
minBalance = 300    # 账户最小资金余额(买入时)

# 全局变量
arrNet = []
arrMsg = []
acc = None

def findOrder (orderId, NumOfTimes, ordersList = []) :
    for j in range(NumOfTimes) :
        orders = None
        if len(ordersList) == 0:
            orders = _C(exchange.GetOrders)
        else :
            orders = ordersList
        for i in range(len(orders)):
            if orderId == orders[i]["Id"]:
                return True
        Sleep(1000)
    return False

def cancelOrder (price, orderType) :
    orders = _C(exchange.GetOrders)
    for i in range(len(orders)) : 
        if price == orders[i]["Price"] and orderType == orders[i]["Type"]: 
            exchange.CancelOrder(orders[i]["Id"])
            Sleep(500)

def checkOpenOrders (orders, ticker) :
    global arrNet, arrMsg
    for i in range(len(arrNet)) : 
        if not findOrder(arrNet[i]["id"], 1, orders) and arrNet[i]["state"] == "pending" :
            orderId = exchange.Sell(arrNet[i]["coverPrice"], arrNet[i]["amount"], arrNet[i], ticker)
            if orderId :
                arrNet[i]["state"] = "cover"
                arrNet[i]["id"] = orderId                
            else :
                # 撤销
                cancelOrder(arrNet[i]["coverPrice"], ORDER_TYPE_SELL)
                arrMsg.append("挂单失败!" + json.dumps(arrNet[i]) + ", time:" + _D())

def checkCoverOrders (orders, ticker) :
    global arrNet, arrMsg
    for i in range(len(arrNet)) : 
        if not findOrder(arrNet[i]["id"], 1, orders) and arrNet[i]["state"] == "cover" :
            arrNet[i]["id"] = -1
            arrNet[i]["state"] = "idle"
            Log(arrNet[i], "节点平仓,重置为空闲状态。", "#FF0000")


def onTick () :
    global arrNet, arrMsg, acc

    ticker = _C(exchange.GetTicker)    # 每次获取当前最新的行情
    for i in range(len(arrNet)):       # 遍历所有网格节点,根据当前行情,找出需要挂单的位置,挂买单。
        if i != len(arrNet) - 1 and arrNet[i]["state"] == "idle" and ticker.Sell > arrNet[i]["price"] and ticker.Sell < arrNet[i + 1]["price"]:
            acc = _C(exchange.GetAccount)
            if acc.Balance < minBalance :     # 如果钱不够了,只能跳出,什么都不做了。
                arrMsg.append("资金不足" + json.dumps(acc) + "!" + ", time:" + _D())
                break

            orderId = exchange.Buy(arrNet[i]["price"], arrNet[i]["amount"], arrNet[i], ticker) # 挂买单
            if orderId : 
                arrNet[i]["state"] = "pending"   # 如果买单挂单成功,更新网格节点状态等信息
                arrNet[i]["id"] = orderId
            else :
                # 撤单
                cancelOrder(arrNet[i]["price"], ORDER_TYPE_BUY)    # 使用撤单函数撤单
                arrMsg.append("挂单失败!" + json.dumps(arrNet[i]) + ", time:" + _D())
    Sleep(1000)
    orders = _C(exchange.GetOrders)    
    checkOpenOrders(orders, ticker)    # 检测所有买单的状态,根据变化做出处理。
    Sleep(1000)
    orders = _C(exchange.GetOrders)    
    checkCoverOrders(orders, ticker)   # 检测所有卖单的状态,根据变化做出处理。

    # 以下为构造状态栏信息,可以查看FMZ API 文档。
    tbl = {
        "type" : "table", 
        "title" : "网格状态",
        "cols" : ["节点索引", "详细信息"], 
        "rows" : [], 
    }    

    for i in range(len(arrNet)) : 
        tbl["rows"].append([i, json.dumps(arrNet[i])])

    errTbl = {
        "type" : "table", 
        "title" : "记录",
        "cols" : ["节点索引", "详细信息"], 
        "rows" : [], 
    }

    orderTbl = {
     	"type" : "table", 
        "title" : "orders",
        "cols" : ["节点索引", "详细信息"], 
        "rows" : [],    
    }

    while len(arrMsg) > 20 : 
        arrMsg.pop(0)

    for i in range(len(arrMsg)) : 
        errTbl["rows"].append([i, json.dumps(arrMsg[i])])    

    for i in range(len(orders)) : 
        orderTbl["rows"].append([i, json.dumps(orders[i])])

    LogStatus(_D(), "\n", acc, "\n", "arrMsg length:", len(arrMsg), "\n", "`" + json.dumps([tbl, errTbl, orderTbl]) + "`")


def main ():         # 策略执行从这里开始
    global arrNet
    for i in range(int((endPrice - beginPrice) / distance)):        # for 这个循环根据参数构造了网格的数据结构,是一个列表,储存每个网格节点,每个网格节点的信息如下:
        arrNet.append({
            "price" : beginPrice + i * distance,                    # 该节点的价格
            "amount" : amount,                                      # 订单数量
            "state" : "idle",    # pending / cover / idle           # 节点状态
            "coverPrice" : beginPrice + i * distance + pointProfit, # 节点平仓价格
            "id" : -1,                                              # 节点当前相关的订单的ID
        })
        
    while True:    # 构造好网格数据结构后,进入策略主要循环
        onTick()   # 主循环上的处理函数,主要处理逻辑
        Sleep(500) # 控制轮询频率

이 전략의 주요 설계 아이디어는 자신이 관리하는 그리드 데이터 구조를 비교하는 것입니다.GetOrders인터페이스에서 반환된 현재 보류 중인 주문 목록입니다. 보류 중인 주문의 변경 사항(실행 여부와 관계없이)을 분석하고, 그리드 데이터 구조를 업데이트하고, 후속 작업을 수행합니다. 그리고 보류 주문은 가격이 변동하더라도 실행되기 전까지 취소되지 않습니다. 디지털 통화 시장에서는 종종 급등이 발생하기 때문에 이러한 보류 주문은 급등 주문도 받을 수 있습니다(거래소에 보류 주문 수에 제한이 있는 경우) 주문 후에는 조정이 필요합니다).

전략 데이터 시각화를 사용하여LogStatus이 기능은 상태 표시줄에 실시간으로 데이터를 표시합니다.

    tbl = {
        "type" : "table", 
        "title" : "网格状态",
        "cols" : ["节点索引", "详细信息"], 
        "rows" : [], 
    }    

    for i in range(len(arrNet)) : 
        tbl["rows"].append([i, json.dumps(arrNet[i])])

    errTbl = {
        "type" : "table", 
        "title" : "记录",
        "cols" : ["节点索引", "详细信息"], 
        "rows" : [], 
    }

    orderTbl = {
     	"type" : "table", 
        "title" : "orders",
        "cols" : ["节点索引", "详细信息"], 
        "rows" : [],    
    }

세 개의 테이블이 구성됩니다. 첫 번째 테이블은 현재 그리드 데이터 구조의 각 노드에 대한 정보를 표시하고, 두 번째 테이블은 예외 정보를 표시하고, 세 번째 테이블은 거래소의 실제 보류 주문 정보를 표시합니다.

백테스팅

파이썬을 위한 간단한 그리드 전략

파이썬을 위한 간단한 그리드 전략

정책 주소

정책 주소

이 전략은 참조용, 백테스팅 및 테스트용일 뿐입니다. 관심이 있다면 최적화하고 업그레이드할 수 있습니다.