トレンドトラッキング・ショッキング戦略,ストップトラッキング (利益の後に指定された幅の縮小が発生するとストップ)
function CancelPendingOrders() { while (true) { var orders = null; while (!(orders = exchange.GetOrders())) { Sleep(Interval); } if (orders.length == 0) { return; } for (var j = 0; j < orders.length; j++) { exchange.CancelOrder(orders[j].Id, orders[j]); if (j < (orders.length-1)) { Sleep(Interval); } } } } var STATE_WAIT_IDLE = 0; var STATE_WAIT_BUY = 1; var STATE_WAIT_SELL = 2; var STATE_BUY = 3; var STATE_SELL = 4; var State = STATE_WAIT_IDLE; var InitAccount = null; var LastBuyPrice = 0; var LastSellPrice = 0; var LastHighPrice = 0; var LastLowPrice = 0; var LastRecord = null; var Goingshort = false; function onTick(exchange) { var oldState = State; if (State == STATE_WAIT_IDLE) { var records = exchange.GetRecords(); if (!records || records.length < (EMA_Slow + 3)) { return; } // Price not change var newLast = records[records.length-1]; if ((!LastRecord) || (LastRecord.Time == newLast.Time && LastRecord.Close == newLast.Close)) { LastRecord = newLast; return; } LastRecord = newLast; var emaFast = TA.EMA(records, EMA_Fast); var emaSlow = TA.EMA(records, EMA_Slow); if (emaFast[emaFast.length-1] > emaSlow[emaSlow.length-1]) { Goingshort = false; State = STATE_WAIT_BUY; } else if (EnableGoingShort && (emaFast[emaFast.length-1] < emaSlow[emaSlow.length-1])) { Goingshort = true; State = STATE_WAIT_SELL; } else { return; } } var ticker = _C(exchange.GetTicker); // 重新设置这两个参数 if (oldState == STATE_WAIT_IDLE && State != STATE_WAIT_IDLE) { LastLowPrice = ticker.Last; LastHighPrice = ticker.Last; } // 做多 if (!Goingshort) { if (State == STATE_WAIT_BUY) { var lastDownRatio = Math.abs((LastHighPrice - LastLowPrice) / LastHighPrice) * 100; var currentUpRatio = Math.abs((ticker.Last - LastLowPrice) / ticker.Last) * 100; if (lastDownRatio > RatioDown && currentUpRatio > (RatioDown*(UpWeightingVal/100))) { State = STATE_BUY; } else { LastHighPrice = Math.max(LastHighPrice, ticker.Last); LastLowPrice = Math.min(LastLowPrice, ticker.Last); } } else if (State == STATE_WAIT_SELL) { var ratioStopLoss = Math.abs((LastHighPrice - ticker.Last) / LastHighPrice) * 100; var ratioStopProfit = Math.abs((ticker.Last - LastBuyPrice) / LastBuyPrice) * 100; var ratioMaxUp = Math.abs((LastHighPrice - LastBuyPrice) / LastBuyPrice) * 100; if (ticker.Last < LastBuyPrice && ratioStopLoss >= StopLoss) { State = STATE_SELL; Log("开始止损, 当前下跌点数:", _N(ratioStopLoss), "当前价格", ticker.Last, "对比价格", _N(LastHighPrice)); } else if (ticker.Last > LastBuyPrice && ticker.Last < LastHighPrice && ratioStopProfit <= (ratioMaxUp*StopProfitThreshold)) { State = STATE_SELL; Log("开始止赢, 当前上涨点数:", _N(ratioStopProfit), "当前价格", ticker.Last, "对比价格", _N(LastBuyPrice)); } LastHighPrice = Math.max(LastHighPrice, ticker.Last); } } else { if (State == STATE_WAIT_SELL) { var lastUpRatio = Math.abs((LastHighPrice - LastLowPrice) / LastHighPrice) * 100; var currentDownRatio = Math.abs((LastHighPrice - ticker.Last) / LastHighPrice) * 100; if (lastUpRatio > RatioUp && currentDownRatio > (RatioUp*(DownWeightingVal/100))) { State = STATE_SELL; } else { LastHighPrice = Math.max(LastHighPrice, ticker.Last); LastLowPrice = Math.min(LastLowPrice, ticker.Last); } } else if (State == STATE_WAIT_BUY) { var ratioStopLoss = Math.abs((ticker.Last - LastLowPrice) / LastLowPrice) * 100; var ratioStopProfit = Math.abs((LastSellPrice - ticker.Last) / LastSellPrice) * 100; var ratioMaxDown = Math.abs((LastSellPrice - LastLowPrice) / LastSellPrice) * 100; if (ticker.Last > LastSellPrice && ratioStopLoss >= StopLoss) { State = STATE_BUY; Log("开始止损, 当前上涨点数:", _N(ratioStopLoss), "当前价格", ticker.Last, "对比价格", _N(LastSellPrice)); } else if (ticker.Last < LastSellPrice && ticker.Last > LastLowPrice && ratioStopProfit <= (ratioMaxDown*StopProfitThreshold)) { State = STATE_BUY; Log("开始止盈, 当前下跌点数:", _N(ratioStopProfit), "当前价格", ticker.Last, "对比价格", _N(LastLowPrice)); } LastHighPrice = Math.max(LastHighPrice, ticker.Last); LastLowPrice = Math.min(LastLowPrice, ticker.Last); } } if (State != STATE_BUY && State != STATE_SELL) { return; } // Buy or Sell, Cancel pending orders first CancelPendingOrders(); var account = _C(exchange.GetAccount); // 做多 if (!Goingshort) { if (State == STATE_BUY) { var price = ticker.Sell + SlidePrice; var amount = _N(account.Balance*0.99 / price); if (amount >= MinStock) { if (exchange.Buy(price, amount, "做多")) { LastBuyPrice = LastHighPrice = price; } else { Log("开多仓失败", price, amount, account); } } else { State = STATE_WAIT_SELL; } } else { var sellAmount = account.Stocks - InitAccount.Stocks; if (sellAmount > MinStock) { exchange.Sell(ticker.Buy - SlidePrice, sellAmount); } else { // No stocks, wait buy and log profit LogProfit(account.Balance - InitAccount.Balance, account); State = STATE_WAIT_IDLE; } } } else { if (State == STATE_BUY) { var price = ticker.Sell + SlidePrice; var amount = Math.min(_N(account.Balance*0.99 / price), InitAccount.Stocks - account.Stocks); if (amount >= MinStock) { exchange.Buy(price, amount); } else { LogProfit(account.Balance - InitAccount.Balance, account); State = STATE_WAIT_IDLE; } } else { var price = ticker.Buy - SlidePrice; var sellAmount = account.Stocks; if (sellAmount > MinStock) { exchange.Sell(ticker.Last - SlidePrice, sellAmount, "做空"); LastSellPrice = LastLowPrice = price; } else { // No stocks, wait buy and log profit State = STATE_WAIT_BUY; } } } } function main() { InitAccount = _C(exchange.GetAccount); Log(exchange.GetName(), exchange.GetCurrency(), InitAccount); EnableGoingShort = EnableGoingShort && (InitAccount.Stocks > MinStock); LoopInterval = Math.max(LoopInterval, 1); while (true) { onTick(exchange); Sleep(LoopInterval*1000); } }