Không có nhiều chiến lược Python trên hình vuông chiến lược. Một phiên bản Python của chiến lược lưới được viết ở đây. Nguyên tắc của chiến lược rất đơn giản. Một loạt các nút lưới được tạo ra bởi một khoảng cách giá cố định trong phạm vi giá. Khi thị trường thay đổi và giá đạt đến vị trí giá nút lưới, lệnh mua được đặt. Khi lệnh được đóng, tức là, theo giá của lệnh đang chờ cộng với chênh lệch lợi nhuận, chờ lệnh bán để đóng vị trí.
Không cần phải nói rằng rủi ro của chiến lược lưới là bất kỳ chiến lược kiểu lưới nào cũng là đặt cược rằng giá dao động trong một phạm vi nhất định. Một khi giá vượt ra khỏi phạm vi lưới, nó có thể gây ra tổn thất nổi nghiêm trọng. Do đó, mục đích của việc viết chiến lược này là để cung cấp tham chiếu cho ý tưởng viết chiến lược Python hoặc thiết kế chương trình. Chiến lược này chỉ được sử dụng để học và có thể có rủi ro trong bot thực.
Lời giải thích về ý tưởng chiến lược được viết trực tiếp trong các bình luận về mã chiến lược.
'''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
Ý tưởng thiết kế chính của chiến lược là so sánh danh sách hiện tại của các đơn đặt hàng đang chờ được trả về bởiGetOrders
giao diện theo cấu trúc dữ liệu lưới được duy trì bởi chính bạn. Phân tích các thay đổi của các lệnh đang chờ (cho dù chúng được đóng hay không), cập nhật cấu trúc dữ liệu lưới, và thực hiện các hoạt động tiếp theo. Ngoài ra, các lệnh đang chờ sẽ không bị hủy cho đến khi giao dịch hoàn thành, ngay cả khi giá lệch, bởi vì thị trường tiền kỹ thuật số thường có tình huống của các chân, các lệnh đang chờ này cũng có thể nhận được các lệnh của chân (nếu số lượng các lệnh đang chờ được giới hạn trong sàn giao dịch, nó sẽ được điều chỉnh).
Khám phá dữ liệu chiến lược sử dụngLogStatus
chức năng để hiển thị dữ liệu trên thanh trạng thái trong thời gian thực.
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" : [],
}
Ba bảng được xây dựng. Bảng đầu tiên hiển thị thông tin của mỗi nút trong cấu trúc dữ liệu lưới hiện tại, bảng thứ hai hiển thị thông tin bất thường và bảng thứ ba hiển thị thông tin liệt kê thực tế của sàn giao dịch.
Chiến lược là cho mục đích học tập và backtesting chỉ, và nó có thể được tối ưu hóa và nâng cấp nếu bạn quan tâm.