Простая стратегия сетки в версии Python

Автор:Лидия., Создан: 2022-12-23 21:00:45, Обновлено: 2023-09-20 11:17:48

img

Простая стратегия сетки в версии Python

Не так много стратегий 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

# Parameters
beginPrice = 5000   # Grid interval begin price
endPrice = 8000     # Grid interval end price
distance = 20       # Price distance of each grid node
pointProfit = 50    # Profit spread per grid node
amount = 0.01       # Number of pending orders per grid node
minBalance = 300    # Minimum fund balance of the account (at the time of purchase)

# Global variables
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 :
                # Cancel
                cancelOrder(arrNet[i]["coverPrice"], ORDER_TYPE_SELL)
                arrMsg.append("Pending order failed!" + 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], "The node closes the position and resets to the idle state.", "#FF0000")


def onTick () :
    global arrNet, arrMsg, acc

    ticker = _C(exchange.GetTicker)    # Get the latest current ticker every time
    for i in range(len(arrNet)):       # Iterate through all grid nodes, find out the position where you need to pend a buy order according to the current market, and pend a buy order.
        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 :     # If there is not enough money left, you can only jump out and do nothing.
                arrMsg.append("Insufficient funds" + json.dumps(acc) + "!" + ", time:" + _D())
                break

            orderId = exchange.Buy(arrNet[i]["price"], arrNet[i]["amount"], arrNet[i], ticker) # Pending buy orders
            if orderId : 
                arrNet[i]["state"] = "pending"   # Update the grid node status and other information if the buy order is successfully pending
                arrNet[i]["id"] = orderId
            else :
                # Cancel h/the order
                cancelOrder(arrNet[i]["price"], ORDER_TYPE_BUY)    # Cancel orders by using the cancel function
                arrMsg.append("Pending order failed!" + json.dumps(arrNet[i]) + ", time:" + _D())
    Sleep(1000)
    orders = _C(exchange.GetOrders)    
    checkOpenOrders(orders, ticker)    # Check the status of all buy orders and process them according to the changes.
    Sleep(1000)
    orders = _C(exchange.GetOrders)    
    checkCoverOrders(orders, ticker)   # Check the status of all sell orders and process them according to the changes.

    # The following information about the construction status bar can be found in the FMZ API documentation.
    tbl = {
        "type" : "table", 
        "title" : "grid status",
        "cols" : ["node index", "details"], 
        "rows" : [], 
    }    

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

    errTbl = {
        "type" : "table", 
        "title" : "record",
        "cols" : ["node index", "details"], 
        "rows" : [], 
    }

    orderTbl = {
     	"type" : "table", 
        "title" : "orders",
        "cols" : ["node index", "details"], 
        "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 ():         # Strategy execution starts here
    global arrNet
    for i in range(int((endPrice - beginPrice) / distance)):        # The for loop constructs a data structure for the grid based on the parameters, a list that stores each grid node, with the following information for each grid node:
        arrNet.append({
            "price" : beginPrice + i * distance,                    # Price of the node
            "amount" : amount,                                      # Number of orders
            "state" : "idle",    # pending / cover / idle           # Node Status
            "coverPrice" : beginPrice + i * distance + pointProfit, # Node closing price
            "id" : -1,                                              # ID of the current order related to the node
        })
        
    while True:    # After the grid data structure is constructed, enter the main strategy loop
        onTick()   # Processing functions on the main loop, the main processing logic
        Sleep(500) # Control polling frequency

Основная идея разработки стратегии заключается в сравнении текущего списка ожидаемых заказов, возвращенныхGetOrdersАнализируйте изменения ожидаемых заказов (закрыты они или нет), обновляйте структуру данных сетки и выполняйте последующие операции. Кроме того, ожидаемые заказы не будут отменены до завершения транзакции, даже если цена отклоняется, поскольку на рынке цифровой валюты часто наблюдается ситуация с пинсами, эти ожидаемые заказы также могут получать заказы пинсов (если количество ожидаемых заказов ограничено на бирже, оно будет скорректировано).

Визуализация данных стратегии используетLogStatusфункция отображения данных на строке состояния в реальном времени.

    tbl = {
        "type" : "table", 
        "title" : "grid status",
        "cols" : ["node index", "details"], 
        "rows" : [], 
    }    

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

    errTbl = {
        "type" : "table", 
        "title" : "record",
        "cols" : ["node index", "details"], 
        "rows" : [], 
    }

    orderTbl = {
     	"type" : "table", 
        "title" : "orders",
        "cols" : ["node index", "details"], 
        "rows" : [],    
    }

Первая таблица отображает информацию каждого узла в текущей структуре данных сетки, вторая таблица отображает ненормальную информацию, а третья таблица отображает фактическую информацию обмена.

Обратный тест

img img img

Адрес стратегии

Адрес стратегии

Стратегия предназначена только для обучения и тестирования, и ее можно оптимизировать и обновить, если вы заинтересованы.


Связанные

Больше