Il n'y a pas beaucoup de stratégies Python sur le carré de stratégie. Une version Python de la stratégie de grille est écrite ici. Le principe de la stratégie est très simple. Une série de nœuds de grille est générée par une distance de prix fixe dans une plage de prix. Lorsque le marché change et que le prix atteint une position de prix de nœud de grille, un ordre d'achat est placé. Lorsque l'ordre est fermé, c'est-à-dire selon le prix de l'ordre en attente plus l'écart de profit, un ordre de vente est placé pour fermer la position. Capturez les fluctuations dans la plage de prix définie.
Il va sans dire que le risque de la stratégie de grille est que toute stratégie de type grille est un pari que le prix fluctue dans une certaine plage. Une fois que le prix sort de la plage de grille, il peut causer de graves pertes flottantes. Par conséquent, le but de l'écriture de cette stratégie est de fournir une référence pour les idées d'écriture de stratégie Python ou la conception de programme. Cette stratégie est utilisée uniquement pour l'apprentissage et peut être risquée dans le vrai bot.
L'explication des idées stratégiques est écrite directement dans les commentaires du code de stratégie.
'''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
L'idée de conception principale de la stratégie est de comparer la liste actuelle des commandes en attente renvoyées par leGetOrders
l'interface en fonction de la structure de données de la grille maintenue par vous-même. Analysez les modifications des ordres en attente (qu'ils soient fermés ou non), mettez à jour la structure de données de la grille et effectuez des opérations ultérieures. De plus, les ordres en attente ne seront pas annulés jusqu'à ce que la transaction soit terminée, même si le prix dévie, car le marché de la monnaie numérique a souvent la situation des broches, ces ordres en attente peuvent également recevoir les ordres de broches (si le nombre d'ordres en attente est limité dans l'échange, il sera ajusté).
La visualisation des données stratégiques utilise lesLogStatus
fonction d'affichage des données sur la barre d'état en temps réel.
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" : [],
}
Trois tableaux sont construits. Le premier tableau affiche les informations de chaque nœud dans la structure de données de la grille actuelle, le deuxième tableau affiche des informations anormales et le troisième tableau affiche les informations réelles de l'échange.
La stratégie est à des fins d'apprentissage et de backtesting seulement, et elle peut être optimisée et améliorée si vous êtes intéressé.