- 策略广场
- 商品期货布林带套利
商品期货布林带套利
Author:
扫地僧, Date: 2021-11-04 17:11:23
Tags:
商品期货套利JavaScript
/*backtest
start: 2016-01-01 00:00:00
end: 2018-01-30 19:00:00
period: 1m
exchanges: [{"eid":"Futures_CTP","currency":"FUTURES","minfee":3,"fee":[0,0]}]
*/
function NewSymbol(q, a, b) {
var self = {
q: q,
a: a,
b: b
};
self.shortFirst = false;
self.positionsCache = null;
self.initAccount = _C(exchange.GetAccount);
self.GetRecords = function() {
if (!(exchange.IO("status") && $.IsTrading(a) && $.IsTrading(b))) {
return null;
}
var ra = null;
var rb = null;
var da = null;
var db = null;
if (exchange.SetContractType(a)) {
ra = exchange.GetRecords();
da = exchange.GetDepth();
}
if (exchange.SetContractType(b)) {
rb = exchange.GetRecords();
db = exchange.GetDepth();
}
if (!(ra && rb && da && db && ra.length > 0 && rb.length > 0)) {
return null;
}
var newRecords = [];
var isSwitch = false;
if (ra[0].Time < rb[0].Time) {
var tmp = rb;
rb = ra;
ra = tmp;
isSwitch = true;
}
var stop = false;
var j = 0;
for (var i = 0; i < ra.length && !stop; i++) {
while (j < rb.length && rb[j].Time < ra[i].Time) {
j++;
}
if (j >= rb.length) {
break;
}
if (ra[i].Time == rb[j].Time) {
var diff = (ra[i].Close - rb[j].Close) * (isSwitch ? -1 : 1);
newRecords.push({
Time: ra[i].Time,
Close: diff
});
}
}
return {
r: newRecords,
depthA: da,
depthB: db
}
}
self.CancelAll = function() {
while (true) {
var orders = _C(exchange.GetOrders);
if (orders.length == 0) {
break;
}
_.each(orders, function(o) {
exchange.CancelOrder(o.Id);
});
Sleep(500);
}
}
self.Rebalance = function() {
while (true) {
self.CancelAll();
var positions = exchange.GetPosition();
if (!positions) {
Sleep(500);
continue;
}
var posA = null;
var posB = null;
var amountA = 0;
var amountB = 0;
_.each(positions, function(p) {
if (p.ContractType == self.a) {
amountA += p.Amount;
posA = p;
} else if (p.ContractType == self.b) {
amountB += p.Amount;
posB = p;
}
});
var diffAmount = amountA - amountB;
if (diffAmount == 0) {
self.positionsCache = positions;
break;
}
var p = $.NewPositionManager();
if (diffAmount > 0) {
if (posA.Type == PD_LONG || posA.Type == PD_LONG_YD) {
p.OpenShort(self.b, diffAmount);
} else {
p.OpenLong(self.b, diffAmount);
}
} else if (diffAmount < 0) {
if (posB.Type == PD_LONG || posB.Type == PD_LONG_YD) {
p.OpenShort(self.a, -diffAmount);
} else {
p.OpenLong(self.a, -diffAmount);
}
}
}
}
self.OpenDirectSL = function(sellPrice, buyPrice) {
exchange.SetContractType(self.a);
exchange.SetDirection("sell");
exchange.Sell(sellPrice, HedgeAmount);
exchange.SetContractType(self.b);
exchange.SetDirection("buy");
exchange.Buy(buyPrice, HedgeAmount);
self.Rebalance();
}
self.OpenDirectLS = function(buyPrice, sellPrice) {
exchange.SetContractType(self.a);
exchange.SetDirection("buy");
exchange.Buy(buyPrice, HedgeAmount);
exchange.SetContractType(self.b);
exchange.SetDirection("sell");
exchange.Sell(sellPrice, HedgeAmount);
self.Rebalance();
}
self.CoverDirect = function(depthA, depthB, slidePrice) {
var isFirst = true;
while (self.positionsCache.length > 0) {
for (var i = 0; i < self.positionsCache.length; i++) {
var pos = self.positionsCache[i];
exchange.SetContractType(pos.ContractType);
var depth = null;
if (isFirst) {
depth = pos.ContractType == self.a ? depthA : depthB;
} else {
depth = _C(exchange.GetDepth);
}
if (pos.Type == PD_LONG || pos.Type == PD_LONG_YD) {
exchange.SetDirection(pos.Type == PD_LONG ? "closebuy_today" : "closebuy");
exchange.Sell(depth.Bids[0].Price - slidePrice, pos.Amount);
} else {
exchange.SetDirection(pos.Type == PD_SHORT ? "closesell_today" : "closesell");
exchange.Buy(depth.Asks[0].Price + slidePrice, pos.Amount);
}
}
isFirst = false;
Sleep(500);
self.CancelAll();
self.positionsCache = _C(exchange.GetPosition);
}
var account = _C(exchange.GetAccount);
LogProfit(account.Balance - self.initAccount.Balance);
}
self.Open = function(depthA, shortFirst, callback) {
self.shortFirst = shortFirst;
var tasks = self.shortFirst ? ["sell", "buy"] : ["buy", "sell"];
self.q.pushTask(exchange, self.a, tasks[0], 1, function(task, ret) {
self.q.pushTask(exchange, self.b, tasks[1], 1, function(task, ret) {
callback();
})
})
}
self.Cover = function(callback) {
var tasks = self.shortFirst ? ["closesell", "closebuy"] : ["closebuy", "closesell"];
self.q.pushTask(exchange, self.a, tasks[0], 1, function(task, ret) {
self.q.pushTask(exchange, self.b, tasks[1], 1, function(task, ret) {
callback();
})
})
}
return self;
}
// var Ratio = 1
function main() {
SetErrorFilter("login");
var q = $.NewTaskQueue();
var s = NewSymbol(q, Symbol_near, Symbol_far);
var openDiff = 10;
var coverDiff = 3;
var state = 0;
var preAccount = _C(exchange.GetAccount);
var ratio = 0 // 差价递增系数
while (true) {
Sleep(500);
/*
Sleep(1000);
if (q.size() > 0) {
q.poll();
continue;
}
*/
var obj = s.GetRecords();
if (!obj || obj.r.length < 30) {
continue
}
var r = obj.r;
var boll = TA.BOLL(r, N, Boll_rate)
var up = boll[0][boll[0].length - 1];
var mid = boll[1][boll[1].length - 1];
var down = boll[2][boll[2].length - 1];
var slidePrice = 1;
var sellPriceA = obj.depthA.Bids[0].Price - slidePrice;
var buyPriceA = obj.depthB.Asks[0].Price + slidePrice;
var buyPriceB = obj.depthA.Asks[0].Price + slidePrice;
var sellPriceB = obj.depthB.Bids[0].Price - slidePrice;
var diffA = sellPriceA - buyPriceA;
var diffB = buyPriceB - sellPriceB;
var nowTime = r[r.length - 1].Time;
$.PlotLine("UP", up, nowTime);
$.PlotLine("MID", mid, nowTime);
$.PlotLine("Down", down, nowTime);
$.PlotLine("DiffA", diffA, nowTime);
$.PlotLine("DiffB", diffB, nowTime);
if (state == 0) {
if (diffA > up && up - mid > limit) {
Log("Diff", diffA, "up:", up);
$.PlotFlag(nowTime, "Short " + diffA, "S");
state = 1;
/*
s.Open(true, function() {
hasOpen = true;
});
*/
s.OpenDirectSL(sellPriceA, buyPriceA);
ratio += Ratio
} else if (diffB < down && mid - down > limit) {
state = 2;
Log("Diff", diffB, "down:", down);
$.PlotFlag(nowTime, "Long " + diffB, "L");
s.OpenDirectLS(buyPriceB, sellPriceB);
/*
s.Open(false, function() {
hasOpen = true;
});
*/
ratio += Ratio
}
} else {
if ((state == 1 && diffB < mid) || (state == 2 && diffA > mid)) {
$.PlotFlag(nowTime, "Cover diffA:" + diffA + "diffB:" + diffB, "C");
s.CoverDirect(obj.depthA, obj.depthB, slidePrice);
state = 0;
// ratio 重置
ratio = 0
/*
s.Cover(function() {
state = 0;
var account = _C(exchange.GetAccount);
if (account) {
Log("mid", mid, account);
$.PlotFlag(new Date().getTime(), "Profit " + _N(account.Balance - preAccount.Balance), "C");
LogProfit(account.Balance);
preAccount = account;
}
});
*/
} else if(state == 1 && diffA > (up + ratio * Math.abs(up - mid)) && up - mid > limit){ // 触发加仓, 加正套
Log("Diff", diffA, "up:", up);
$.PlotFlag(nowTime, "Short " + diffA, "AS");
s.OpenDirectSL(sellPriceA, buyPriceA);
ratio += Ratio
} else if(state == 2 && diffB < (down - ratio * Math.abs(mid - down)) && mid - down > limit){
Log("Diff", diffB, "down:", down);
$.PlotFlag(nowTime, "Long " + diffB, "AL");
s.OpenDirectLS(buyPriceB, sellPriceB);
ratio += Ratio
}
}
}
}
/*
1、 BUG 开仓平仓 函数中有 一边 没有设置 对冲量参数, 下单量写的还是 1
2、 系数 反对冲的时候要是 减去。1 +/- ratio
*/
相关内容
更多内容