/// <summary>Called when new data is received</summary> public override void Step() { base.Step(); if (!Instrument.NewCandle) { return; } var position = Positions.FirstOrDefault(); if (position == null) { var snr = new SnR(Instrument, tf: TimeFrame.Hour8); var mcs = Instrument.MCS; // Look for price being near an SnR level var price = Instrument.LatestPrice; var near = snr.Nearest(price.Mid, 0); if (near == null || Math.Abs(near.Price - price.Mid) > 0.5 * mcs) { return; } // Get the preceding trend var trend = Instrument.MeasureTrendFromCandles(-5, 1); } }
/// <summary></summary> protected override void StepCore() { // If the SL is on the winning side, let the trade run its course var sl_rel = Position.StopLossRel(); if (sl_rel < 0) { return; } var mcs = Instrument.MCS; var sign = Position.Sign(); var price = Instrument.LatestPrice; var trend_sign_slow = Strategy.TrendSignSlow; var trend_sign_fast = Strategy.TrendSignFast; // If the position opposes the slow trend, try to close it at break even if (sign == -trend_sign_slow && sign == -trend_sign_fast) { var cp = price.Price(-sign); // Choose a SL based on SnR levels var snr = new SnR(Instrument); Debugging.Dump(snr); var near = snr.Nearest(cp, -sign, min_dist: mcs * 0.5); var sl = near != null ? near.Price : cp - sign * mcs; if (Math.Abs(sl - Position.EntryPrice) < sl_rel) { Broker.ModifyOrder(Instrument, Position, sl: sl); Debugging.Trace(" +Position opposes the trend (trend={0}), closing at break even".Fmt(trend_sign_slow)); return; } } // If the trade is better than RtR=1:1, and the close probability is high close the trade // For closing positions, use Ask when the price is high, Bit when the price is low var prob_sign = Strategy.ProbSign; var prob = Strategy.Prob(prob_sign); if (sign == prob_sign && Math.Abs(prob) > StrategyPriceDistribution.ClosePositionProb) { // If the price gradient is in the direction of the trade, don't close it var d = Instrument.HighRes.FirstDerivative(-1); if (Math.Sign(d) == sign) { return; } var min_profit = Instrument.Symbol.QuoteToAcct(sl_rel * Position.Volume); if (Position.NetProfit > min_profit) { Debugging.Trace(" +Close Prob: {0}".Fmt(prob)); Broker.ClosePosition(Position); } } }
/// <summary>Called when new data is received</summary> public override void Step() { base.Step(); using (Broker.SuspendRiskCheck(ignore_risk: true)) { const double TakeProfitFrac = 1.020; const double ReverseFrac = 0.998; Dump(); // The unit of volume to trade var mcs = Instrument.MCS; var ep = Instrument.LatestPrice.Mid; var vol = Broker.ChooseVolume(Instrument, 5.0 * mcs); // Open a trade in the direction of the trend if (ProfitSign == 0) { Dump(); Debugging.Trace("Idx={0},Tick={1} - Setting profit sign ({2}) - Equity = ${3}".Fmt(Instrument.Count, Bot.TickNumber, TrendSign, Equity)); var tt = CAlgo.SignToTradeType(TrendSign); var trade = new Trade(Instrument, tt, Label, ep, null, null, vol); Broker.CreateOrder(trade); LastEquity = Equity; } // While the profit direction is the same as the trend direction // look for good spots to add hedged pending orders if (ProfitSign == TrendSign) { // If the current price is at a SnR level, add pending orders on either side. // Hopefully price will reverse at the SnR level and only trigger one of the pending orders. // If price then reverses we can sell an existing profitable trade and be left with the // profit direction going in the right direction var snr = new SnR(Instrument, ep); var lvl_above = snr.Nearest(ep, +1, min_dist: 0.5 * mcs, min_strength: 0.7); var lvl_below = snr.Nearest(ep, -1, min_dist: 0.5 * mcs, min_strength: 0.7); // Choose price levels for the pending orders var above = lvl_above != null ? lvl_above.Price + 0.5 * mcs : ep + mcs; var below = lvl_below != null ? lvl_below.Price - 0.5 * mcs : ep - mcs; // Only recreate if necessary if (!PendingOrders.Any(x => x.TradeType == TradeType.Buy && Maths.FEql(x.TargetPrice, above, 5 * Instrument.PipSize)) || !PendingOrders.Any(x => x.TradeType == TradeType.Sell && Maths.FEql(x.TargetPrice, below, 5 * Instrument.PipSize))) { Dump(); Debugging.Dump(snr); Debugging.Trace("Idx={0},Tick={1} - Adjusting pending orders - Equity = ${2}".Fmt(Instrument.Count, Bot.TickNumber, Equity)); // Cancel any other pending orders further away than these too Broker.CancelAllPendingOrders(Label); var buy = new Trade(Instrument, TradeType.Buy, Label, above, null, null, vol); var sel = new Trade(Instrument, TradeType.Sell, Label, below, null, null, vol); Broker.CreatePendingOrder(buy); Broker.CreatePendingOrder(sel); } } // If the profit is against the Trend, do nothing until losing a fraction of last equity if (ProfitSign != TrendSign && Equity < ReverseFrac * LastEquity) { Dump(); Debugging.Trace("Idx={0},Tick={1} - Changing profit sign to ({2}) - Equity = ${3}".Fmt(Instrument.Count, Bot.TickNumber, TrendSign, Equity)); var sign = -ProfitSign; // Try to reverse the sign by closing profitable positions foreach (var pos in Positions.Where(x => x.Sign() != sign && x.NetProfit > 0).OrderBy(x => - x.NetProfit).ToArray()) { Broker.ClosePosition(pos); // Break out when the profit direction has been reversed if (ProfitSign == sign) { break; } } // Couldn't reverse the sign by closing positions, open a new one if (ProfitSign != sign) { var tt = CAlgo.SignToTradeType(sign); var reverse_vol = Math.Abs(NetVolume) + vol; var trade = new Trade(Instrument, tt, Label, ep, null, null, reverse_vol); Broker.CreateOrder(trade); } LastEquity = Equity; } // If equity is greater than a threshold, take profits if (Equity > TakeProfitFrac * LastEquity) { Dump(); Debugging.Trace("Idx={0},Tick={1} - Profit taking - Equity = ${2}".Fmt(Instrument.Count, Bot.TickNumber, Equity)); var sign = ProfitSign; foreach (var pos in Positions.Where(x => x.Sign() == sign && x.NetProfit > 0).OrderBy(x => - x.NetProfit).ToArray()) { if (pos.Volume >= Math.Abs(NetVolume)) { continue; } Broker.ClosePosition(pos); } LastEquity = Equity; } } }