The basics
Illustrated
Dual Thrust 策略包含完整的图表显示, 图表动态更新,模板引用等功能, 可做学习模板使用.
The following is a detailed description of the strategy:http://xueqiu.com/5256769224/32429363
var ChartCfg = { __isStock: true, title: { text: 'Dual Thrust 上下轨图' }, yAxis: { plotLines: [{ value: 0, color: 'red', width: 2, label: { text: '上轨', align: 'center' }, }, { value: 0, color: 'green', width: 2, label: { text: '下轨', align: 'center' }, }] }, series: [{ type: 'candlestick', name: '当前周期', id: 'primary', data: [] }, { type: 'flags', onSeries: 'primary', data: [], }] }; var STATE_IDLE = 0; var STATE_LONG = 1; var STATE_SHORT = 2; var State = STATE_IDLE; var LastBarTime = 0; var UpTrack = 0; var BottomTrack = 0; var chart = null; var InitAccount = null; var LastAccount = null; var Counter = { w: 0, l: 0 }; function _N(v) { return Decimal(v).toSD(4, 1).toNumber(); } function GetPosition(posType) { var positions = exchange.GetPosition(); for (var i = 0; i < positions.length; i++) { if (positions[i].Type === posType) { return [positions[i].Price, positions[i].Amount]; } } return [0, 0]; } function CancelPendingOrders() { while (true) { var orders = exchange.GetOrders(); for (var i = 0; i < orders.length; i++) { exchange.CancelOrder(orders[i].Id); Sleep(Interval); } if (orders.length === 0) { break; } } } function Trade(currentState, nextState) { var pfn = nextState === STATE_LONG ? exchange.Buy : exchange.Sell; if (currentState !== STATE_IDLE) { exchange.SetDirection(currentState === STATE_LONG ? "closebuy" : "closesell"); while (true) { var amount = GetPosition(currentState === STATE_LONG ? PD_LONG : PD_SHORT)[1]; if (amount === 0) { break; } // pfn(amount); pfn(nextState === STATE_LONG ? _C(exchange.GetTicker).Sell * 1.001 : _C(exchange.GetTicker).Buy * 0.999, amount); Sleep(Interval); CancelPendingOrders(); }; var account = exchange.GetAccount(); if (account.Stocks > LastAccount.Stocks) { Counter.w++; } else { Counter.l++; } LogProfit(_N(account.Stocks - InitAccount.Stocks), "收益率:", _N((account.Stocks - InitAccount.Stocks) * 100 / InitAccount.Stocks) + '%'); LastAccount = account; } exchange.SetDirection(nextState === STATE_LONG ? "buy" : "sell"); while (true) { var pos = GetPosition(nextState === STATE_LONG ? PD_LONG : PD_SHORT); if (pos[1] >= AmountOP) { Log("持仓均价", pos[0], "数量:", pos[1]); break; } // pfn(AmountOP-pos[1]); pfn(nextState === STATE_LONG ? _C(exchange.GetTicker).Sell * 1.001 : _C(exchange.GetTicker).Buy * 0.999, AmountOP-pos[1]); Sleep(Interval); CancelPendingOrders(); } } function onTick(exchange) { var records = exchange.GetRecords(); if (!records || records.length <= NPeriod) { return; } var Bar = records[records.length - 1]; if (LastBarTime !== Bar.Time) { var HH = TA.Highest(records, NPeriod, 'High'); var HC = TA.Highest(records, NPeriod, 'Close'); var LL = TA.Lowest(records, NPeriod, 'Low'); var LC = TA.Lowest(records, NPeriod, 'Close'); var Range = Math.max(HH - LC, HC - LL); UpTrack = _N(Bar.Open + (Ks * Range)); DownTrack = _N(Bar.Open - (Kx * Range)); if (LastBarTime > 0) { var PreBar = records[records.length - 2]; chart.add(0, [PreBar.Time, PreBar.Open, PreBar.High, PreBar.Low, PreBar.Close], -1); } else { for (var i = Math.min(records.length, NPeriod * 3); i > 1; i--) { var b = records[records.length - i]; chart.add(0, [b.Time, b.Open, b.High, b.Low, b.Close]); } } chart.add(0, [Bar.Time, Bar.Open, Bar.High, Bar.Low, Bar.Close]); ChartCfg.yAxis.plotLines[0].value = UpTrack; ChartCfg.yAxis.plotLines[1].value = DownTrack; ChartCfg.subtitle = { text: '上轨: ' + UpTrack + ' 下轨: ' + DownTrack }; chart.update(ChartCfg); chart.reset(PeriodShow); LastBarTime = Bar.Time; } else { chart.add(0, [Bar.Time, Bar.Open, Bar.High, Bar.Low, Bar.Close], -1); } LogStatus("Price:", Bar.Close, "Up:", UpTrack, "Down:", DownTrack, "Wins: ", Counter.w, "Losses:", Counter.l, "Date:", new Date()); var msg; if (State === STATE_IDLE || State === STATE_SHORT) { if (Bar.Close >= UpTrack) { msg = '做多 触发价: ' + Bar.Close + ' 上轨:' + UpTrack; Log(msg); Trade(State, STATE_LONG); State = STATE_LONG; chart.add(1, {x:Bar.Time, color: 'red', shape: 'flag', title: '多', text: msg}); } } if (State === STATE_IDLE || State === STATE_LONG) { if (Bar.Close <= DownTrack) { msg = '做空 触发价: ' + Bar.Close + ' 下轨:' + DownTrack; Log(msg); Trade(State, STATE_SHORT); chart.add(1, {x:Bar.Time, color: 'green', shape: 'circlepin', title: '空', text: msg}); State = STATE_SHORT; } } } function onexit() { var pos = exchange.GetPosition(); if (pos.length > 0) { Log("警告, 退出时有持仓", pos); } } function main() { if (exchange.GetName() !== 'Futures_OKCoin') { throw "只支持OKCoin期货"; } exchange.SetRate(1); exchange.SetContractType(["this_week", "next_week", "quarter"][ContractTypeIdx]); exchange.SetMarginLevel([10, 20][MarginLevelIdx]); if (exchange.GetPosition().length > 0) { throw "策略启动前不能有持仓."; } CancelPendingOrders(); InitAccount = LastAccount = exchange.GetAccount(); LoopInterval = Math.min(1, LoopInterval); Log('交易平台:', exchange.GetName(), InitAccount); LogStatus("Ready..."); LogProfitReset(); chart = Chart(ChartCfg); chart.reset(); LoopInterval = Math.max(LoopInterval, 1); while (true) { onTick(exchange); Sleep(LoopInterval * 1000); } }
a624587332This strategy is really cocky, it's just rude.
dayTrader2018What's the point of assigning an amount to pfn? What's the point of assigning an amount to pfn?
Selling outCan commodity futures be retested?
xuanxuan good
Zero 商品期货改一下Trade函数就能兼容了.