资源加载中... loading...

商品期货布林带套利

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
*/ 
template: strategy.tpl:40:21: executing "strategy.tpl" at <.api.GetStrategyListByName>: wrong number of args for GetStrategyListByName: want 7 got 6