In the previous article, we implemented a simple spot order supervising bot, and today we are going to implement a contract version of a simple order supervising bot.
There is a big difference between the order supervising bot of the contract version and the spot version. The spot order supervising can mainly be realized by monitoring the changes of account assets. The futures version needs to monitor the position changes in an account. Therefore, the situation of the futures version is more complicated, because there are different contracts for long and short positions of futures, which needs to deal with a series of details. The core idea is to monitor the position changes, and to trigger the order-supervising action based on the position changes. It was originally designed to deal with long and short positions together, but we found it would be complicated to deal with that. After analyzing the problem, it is decided to deal with the long and short positions separately.
Strategy Parameter:
It supports backtest, and can directly use the default settings to backtest for observation.
Source code:
/*backtest
start: 2021-03-18 00:00:00
end: 2021-04-07 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD"},{"eid":"Futures_OKCoin","currency":"BTC_USD"},{"eid":"Futures_OKCoin","currency":"BTC_USD"}]
*/
function test() {
// test function
var ts = new Date().getTime()
if (ts % (1000 * 60 * 60 * 6) > 1000 * 60 * 60 * 5.5) {
Sleep(1000 * 60 * 10)
var nowPosAmount = getPosAmount(_C(exchange.GetPosition), refCt)
var longPosAmount = nowPosAmount.long
var shortPosAmount = nowPosAmount.short
var x = Math.random()
if (x > 0.7) {
exchange.SetDirection("buy")
exchange.Buy(-1, _N(Math.max(1, x * 10), 0), "the reference account tests ordering#FF0000")
} else if(x < 0.2) {
exchange.SetDirection("sell")
exchange.Sell(-1, _N(Math.max(1, x * 10), 0), "the reference account tests ordering#FF0000")
} else if(x >= 0.2 && x <= 0.5 && longPosAmount > 4) {
exchange.SetDirection("closebuy")
exchange.Sell(-1, longPosAmount, "the reference account tests closing positions#FF0000")
} else if(shortPosAmount > 4) {
exchange.SetDirection("closesell")
exchange.Buy(-1, _N(shortPosAmount / 2, 0), "he reference account tests closing position#FF0000")
}
}
}
function getPosAmount(pos, ct) {
var longPosAmount = 0
var shortPosAmount = 0
_.each(pos, function(ele) {
if (ele.ContractType == ct && ele.Type == PD_LONG) {
longPosAmount = ele.Amount
} else if (ele.ContractType == ct && ele.Type == PD_SHORT) {
shortPosAmount = ele.Amount
}
})
return {long: longPosAmount, short: shortPosAmount}
}
function trade(e, ct, type, delta) {
var nowPosAmount = getPosAmount(_C(e.GetPosition), ct)
var nowAmount = type == PD_LONG ? nowPosAmount.long : nowPosAmount.short
if (delta > 0) {
// open position
var tradeFunc = type == PD_LONG ? e.Buy : e.Sell
e.SetDirection(type == PD_LONG ? "buy" : "sell")
tradeFunc(-1, delta)
} else if (delta < 0) {
// close position
var tradeFunc = type == PD_LONG ? e.Sell : e.Buy
e.SetDirection(type == PD_LONG ? "closebuy" : "closesell")
if (nowAmount <= 0) {
Log("no position detected")
return
}
tradeFunc(-1, Math.min(nowAmount, Math.abs(delta)))
} else {
throw "error"
}
}
function main() {
LogReset(1)
if (exchanges.length < 2) {
throw "no platform with order supervision"
}
var exName = exchange.GetName()
// detect the platform for reference
if (!exName.includes("Futures_")) {
throw "only support futures order supervising"
}
Log("start monitoring", exName, "platform", "#FF0000")
// detect the order supervising platform
for (var i = 1 ; i < exchanges.length ; i++) {
if (exchanges[i].GetName() != exName) {
throw "The order supervising platform is different from the reference platform!"
}
}
// set trading pair and contract
_.each(exchanges, function(e) {
if (!IsVirtual()) {
e.SetCurrency(refCurrency)
if (isSimulate) {
if (e.GetName() == "Futures_OKCoin") {
e.IO("simulate", true)
}
}
}
e.SetContractType(refCt)
})
var initRefPosAmount = getPosAmount(_C(exchange.GetPosition), refCt)
while(true) {
if (IsVirtual()) { // only simulate during backtest
test() // test function, which simulates a reference account to trade automatically, to trigger the order supervising of the account
}
Sleep(5000)
var nowRefPosAmount = getPosAmount(_C(exchange.GetPosition), refCt)
var tbl = {
type : "table",
title : "position",
cols : ["name", "label", "long", "short", "account asset (Stocks)", "account assest (Balance)"],
rows : []
}
_.each(exchanges, function(e) {
var pos = getPosAmount(_C(e.GetPosition), refCt)
var acc = _C(e.GetAccount)
tbl.rows.push([e.GetName(), e.GetLabel(), pos.long, pos.short, acc.Stocks, acc.Balance])
})
LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`")
// calculate the position amount of change
var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short
// detect the change
if (longPosDelta == 0 && shortPosDelta == 0) {
continue
} else {
// detect the position change
for (var i = 1 ; i < exchanges.length ; i++) {
// execute the action of long
if (longPosDelta != 0) {
Log(exchanges[i].GetName(), exchanges[i].GetLabel(), "Execute long order supervising, amount of change:", longPosDelta)
trade(exchanges[i], refCt, PD_LONG, longPosDelta)
}
// execute the action of short
if (shortPosDelta != 0) {
Log(exchanges[i].GetName(), exchanges[i].GetLabel(), "Execute short order supervising, amount of change:", shortPosDelta)
trade(exchanges[i], refCt, PD_SHORT, shortPosDelta)
}
}
}
// after the operation of order supervising, update
initRefPosAmount = nowRefPosAmount
}
}
In consideration of the fact that after OKEX updated the V5 interface, and the OKEX simulated bot can be used, I used API KAYs of two OKEX simulated bots to test, very conveniently.
The first exchange object to be added is the reference platform, and the order supervising platform follows the account of the reference platform to operate. On the OKEX simulated bot page, the reference platform account manually places 3 ETH quarterly crypto-margined contracts.
It can be seen that the bot detected the position changes, and the following operations.
Let’s try to close the 2 contract positions that we just opened. The positions after closing the positions are shown in the figure:
The bot followed to operate and closed 2 contracts.
The strategy is designed in a simple and easy-to-understand way without optimization. The improved part also needs to deal with details such as asset detection when supervising orders. In order to simplify the design, market orders are used for order supervising orders. The strategy only provides learning ideas, and the bot can be optimized according to your needs.
Strategy address: https://www.fmz.com/strategy/270012
Welcome to leave your comments.