///// <summary>Called when new data is received</summary> //public override void Step() //{ // var current_price = Instrument.CurrentPrice(0); // var sym = Instrument.Symbol; // // Find the stats for the recent price history // PriceStats.Add((double)current_price); // // Synchronise the Positions with our list // SynchroniseLivePositions(); // // Measure the current net position // var net = NetPosition; // // If the sum of all trades is greater than the threshold, cash in // // If the sum of all trades exceeds 90% of the balance to risk, bail out // var profit_threshold = Misc.Max(1.0, Broker.Balance * TakeProfitPC); // if (net > profit_threshold) // { // CloseOut(); // return; // Return so that closed positions get output while debugging // } // if (net < -BalanceRisked) // { // CloseOut(); // return; // Return so that closed positions get output while debugging // } // // Attempt to compress the positions // for (;Positions.Count > 2;) // { // var pos0 = Positions.Back(0); // var pos1 = Positions.Back(1); // if (pos0.NetProfit + pos1.NetProfit > 1.0) // { // Broker.ClosePosition(pos0); // Broker.ClosePosition(pos1); // continue; // } // break; // } // // If we have no position, make a trade // if (Positions.Count == 0) // { // // Get the current price direction // var q = Quadratic.FromPoints( // new v2(-2f, (float)Instrument[-2].Median), // new v2(-1f, (float)Instrument[-1].Median), // new v2(-0f, (float)Instrument[-0].Median)); // var next_price =(QuoteCurrency)q.F(1.0); // var tt = next_price > current_price ? TradeType.Buy : TradeType.Sell; // var sign = tt.Sign(); // // Create the initial trade // var volume = sym.VolumeMin; // var risk = Broker.MaxSL(Instrument, volume); // var ep = Instrument.CurrentPrice(sign); // var tp = ep + sign * risk; // var sl = ep - sign * risk; // var trade = new Trade(Instrument, tt, Label, ep, sl, tp, volume); // // Record how much we're risking on this set of trades // BalanceRisked = sym.QuoteToAcct(risk * volume); // // Open the position // var pos = Broker.CreateOrder(trade); // if (pos != null) // Positions.Add(pos); // } // else // { // // Get the loss threshold given the current number of trades // var loss_per_level = BalanceRisked / ReversesCount; // var loss_threshold = Positions.Count * loss_per_level; // // If the net profit has dropped below the threshold, open a reverse trade // if (net < -loss_threshold) // { // // The reverse trade is created such that the total risk remains the same. // var prev = Positions.Back(); // var volume = sym.NormalizeVolume(prev.Volume * (Positions.Count + 1) / Positions.Count); // var tt = prev.TradeType.Opposite(); // var ep = Instrument.CurrentPrice(tt.Sign()); // var tp = prev.StopLossAbs(); // var sl = prev.TakeProfitAbs(); // var trade = new Trade(Instrument, tt, Label, ep, sl, tp, volume); // // Open the reverse position // var pos = Broker.CreateOrder(trade); // if (pos != null) // Positions.Add(pos); // } // } // int break_point; // if (Instrument.NewCandle) // break_point = 1; //} ///// <summary>Update the collection 'Positions' with any live positions created by this strategy</summary> //private void SynchroniseLivePositions() //{ // var live_positions = Bot.Positions.ToHashSet(x => x.Id); // Positions.RemoveIf(x => !live_positions.Contains(x.Id)); //} /// <summary>Returns a trade when a likely good trade is identified. Or null</summary> private Trade FindEntry() { // Get the current price direction var q = Quadratic.FromPoints( new v2(-2f, (float)Instrument[-2].Close), new v2(-1f, (float)Instrument[-1].Close), new v2(-0f, (float)Instrument[-0].Close)); // Choose the trade type var curr_price = (double)Instrument.CurrentPrice(0); var next_price = q.F(1.0); var tt = next_price > curr_price ? TradeType.Buy : TradeType.Sell; var sign = tt.Sign(); { // Look for some confirming signals // Does it match the long period EMA? const double ema100_threshold_gradient = 0.1; // pips per index var ema100 = Bot.Indicators.ExponentialMovingAverage(Instrument.Data.Close, 100); var grad100 = ema100.Result.FirstDerivative() / Instrument.MCS; if (Math.Abs(grad100) < ema100_threshold_gradient || Math.Sign(grad100) != sign) { return(null); } // Does it match the short period EMA? const double ema14_threshold_gradient = 0.1f; // pips per index var ema14 = Bot.Indicators.ExponentialMovingAverage(Instrument.Data.Close, 14); var grad14 = ema14.Result.FirstDerivative() / Instrument.MCS; if (Math.Abs(grad14) < ema14_threshold_gradient || Math.Sign(grad14) != sign) { return(null); } // Is the price within the MCS of the long period EMA? if (Math.Abs(curr_price - ema100.Result.LastValue) > Instrument.MCS) { return(null); } // Is the instrument over-bought or over-sold var rsi = Bot.Indicators.RelativeStrengthIndex(Instrument.Data.Close, 14); if (tt == TradeType.Buy && rsi.Result.LastValue > 70.0) { return(null); // Over bought } if (tt == TradeType.Sell && rsi.Result.LastValue < 30.0) { return(null); // Over sold } // Has the current price just left a strong SnR level? // Is there a candle pattern that agrees with the trade } return(new Trade(Instrument, tt, Label)); }
[Test] public void FromPoints() { var a = new v2(0.5f, 0.3f); var b = new v2(0.7f, -0.2f); var c = new v2(1.0f, 0.6f); var q = Quadratic.FromPoints(a, b, c); Assert.Equal(q.F(a.x), a.y, Math_.TinyF); Assert.Equal(q.F(b.x), b.y, Math_.TinyF); Assert.Equal(q.F(c.x), c.y, Math_.TinyF); }
/// <summary>Trade entry signal based on MACD</summary> protected TradeType?SignalMACD() { // Look for minima or maxima in the short period average var macd = Bot.Indicators.MacdCrossOver(26, 12, 9); // Fit a quadratic to the MACD line (blue one) var poly = Quadratic.FromPoints( -2.0, macd.MACD.Last(2), -1.0, macd.MACD.Last(1), -0.0, macd.MACD.Last(0)); // If the quadratic predicts a peak it might be time to buy/sell. var peak_x = poly.StationaryPoints[0]; if (peak_x < -1.0 || peak_x > 0.0) { return(null); } var blue = macd.MACD.LastValue; var red = macd.Signal.LastValue; for (;;) { var minima = poly.ddF(peak_x) > 0; if (minima) // buy? { // MACD must be below the signal line if (blue > red) { break; } return(TradeType.Buy); } else // sell? { // MACD must be above the signal line if (blue < red) { break; } return(TradeType.Sell); } } return(null); }