Пример #1
0
        /// <summary>Strategy step</summary>
        protected override void Step()
        {
            var price = Instrument.LatestPrice;
            var mcs   = Instrument.MCS;
            var slope = MACD.FirstDerivative(0) / Instrument.PipSize;

            // Hold a trade in the direction of the MACD slope
            // Use hysteresis to switch
            var position = Positions.FirstOrDefault();

            if (position == null)
            {
                if (Math.Abs(slope) > SlopeThreshold)
                {
                    var sign  = Math.Sign(slope);
                    var vol   = Instrument.Symbol.VolumeMin;
                    var trade = new Trade(Instrument, CAlgo.SignToTradeType(sign), Label, price.Price(sign), null, null, vol);
                    Broker.CreateOrder(trade);
                }
            }
            else if (Instrument.NewCandle)
            {
                var sign = position.Sign();
                if (Math.Abs(slope) < SlopeThreshold - Hysteresis)
                {
                    Broker.ClosePosition(position, "{0} - Slope Changed".Fmt(R <Rylobot_MACD> .NameOf));
                }
            }
        }
Пример #2
0
        /// <summary>Increase the position size of winning trades</summary>
        private void IncreasePosition()
        {
            var mcs   = Instrument.MCS;
            var price = Instrument.LatestPrice;

            foreach (var set in PositionSets.Values)
            {
                // Base position increases off the initial position
                // The initial position may be closed just before the other positions (hence null is possible)
                var pos0 = Positions.FirstOrDefault(x => x.Id == set[0]);
                if (pos0 == null)
                {
                    continue;
                }

                var sign = pos0.Sign();

                // Get the positions at are the increases
                var positions = Positions.Where(x => set.Contains(x.Id) && x.Sign() == sign).ToArray();
                if (positions.Length >= MaxPositionsPerSet)
                {
                    continue;
                }

                // Get the initial entry price
                var initial_ep = pos0.EntryPrice;

                // Get the level the price needs to have crossed
                var ep = initial_ep + sign * positions.Length * mcs * PositionIncreaseStep;

                // Add to the position every if 'ep' is crossed
                if (Math.Sign(price.Price(sign) - ep) == sign)
                {
                    Dump();

                    // Adjust the SL on existing trades
                    foreach (var pos in positions)
                    {
                        var adj_sl = pos.StopLoss + sign * mcs * PositionIncreaseStep;
                        Broker.ModifyOrder(Instrument, pos, sl: adj_sl);
                    }

                    // Add to the position
                    var sl    = ep - sign * mcs * SLFrac;
                    var vol   = Broker.ChooseVolume(Instrument, mcs, risk: Risk / MaxPositionsPerSet);
                    var trade = new Trade(Instrument, CAlgo.SignToTradeType(sign), Label, ep, sl, pos0.TakeProfit, vol, comment: pos0.Comment);
                    Broker.CreateOrder(trade);
                }
            }
        }
Пример #3
0
        /// <summary>Called when new data is received</summary>
        public override void Step()
        {
            base.Step();
            if (Instrument.NewCandle || Positions.Any() || PendingOrders.Any())
            {
                Dump();
            }

            var sign0 = Math.Sign(EMA0[0].CompareTo(EMA1[0]));
            var sign1 = Math.Sign(EMA0[-1].CompareTo(EMA1[-1]));

            var order    = PendingOrders.FirstOrDefault();
            var position = Positions.FirstOrDefault();

            // Cancel or close positions/orders that are against the trend
            if (order != null && order.Sign() != sign0)
            {
                Broker.CancelPendingOrder(order);
                order = null;
            }
            if (position != null && position.Sign() != sign0)
            {
                Broker.CloseAt(Instrument, position, EMA0[0]);
            }

            // Look for EMA crosses
            if (sign0 != sign1)
            {
                var mcs   = Instrument.MCS;
                var price = EMA0[0] - sign0 * Instrument.Spread;

                if (order == null || Math.Abs(order.TargetPrice - price) > 2)
                {
                    // Cancel any previous pending orders
                    Broker.CancelAllPendingOrders(Label);

                    // Create a pending order at the cross price
                    var sl    = price - sign0 * mcs * 5;
                    var vol   = Broker.ChooseVolume(Instrument, Math.Abs(price - sl), risk: Risk);
                    var trade = new Trade(Instrument, CAlgo.SignToTradeType(sign0), Label, price, sl, null, vol);
                    Broker.CreatePendingOrder(trade);
                }
            }
        }
Пример #4
0
        protected override void OnPositionOpened(Position position)
        {
            // Prevent positions being entered on the same bulge
            EntryCooldown = NonIntersectingCount;

            {            // Adjust the stop loss to allow for slip
                var mcs  = Instrument.MCS;
                var sign = position.Sign();
                var ep   = position.EntryPrice;
                var sl   = ep - sign * mcs * SLFrac;
                Broker.ModifyOrder(Instrument, position, sl: sl);
            }

            // If the main position of a position set opens, create a pending order in the opposite direction.
            // This is designed to catch the case when we choose a break-out trade but it's actually a reversal, or visa-versa.
            var id = Guid_.Parse(position.Comment);

            if (id != null && PositionSets[id.Value].Count == 1)
            {
                var mcs   = Instrument.MCS;
                var sign  = -position.Sign();
                var tt    = CAlgo.SignToTradeType(sign);
                var rel   = Math.Abs(position.EntryPrice - position.StopLoss.Value) * 0.75;
                var ep    = MA0[0] + sign * rel;
                var sl    = ep - sign * mcs * SLFrac;
                var tp    = (QuoteCurrency?)null;
                var vol   = Broker.ChooseVolume(Instrument, Math.Abs(ep - sl), risk: Risk);
                var trade = new Trade(Instrument, tt, Label, ep, sl, tp, vol, comment: Guid.NewGuid().ToString())
                {
                    Expiration = Instrument.ExpirationTime(2)
                };
                Broker.CreatePendingOrder(trade);
            }

            // Close positions if there is a breakout in the wrong direction
            PositionManagers.Add(new PositionManagerBreakOut(this, position, CloseBreakoutPeriods, only_if_in_profit: true));

            // Close positions when they fail to make new peaks
            PositionManagers.Add(new PositionManagerTopDrop(this, position, CloseTopDropCount, only_if_in_profit: true));

            // Close positions when there's a steady stream of adverse candles
            PositionManagers.Add(new PositionManagerAdverseCandles(this, position, CloseAdverseCount));
        }
Пример #5
0
        /// <summary>Strategy step</summary>
        protected override void Step()
        {
            // Look for trade entry
            var sets_count = PositionSets.Count + PendingOrders.Count();

            if (sets_count < MaxPositionSets && EntryCooldown == 0)
            {
                var mcs = Instrument.MCS;
                {
                    var sign  = -1;
                    var ep    = Donchian[0, Bot];
                    var tt    = CAlgo.SignToTradeType(sign);
                    var sl    = ep - sign * mcs * SLFrac;
                    var tp    = (QuoteCurrency?)null;
                    var vol   = Broker.ChooseVolume(Instrument, Math.Abs(ep - sl), risk: Risk);
                    var trade = new Trade(Instrument, tt, Label, ep, sl, tp, vol, comment: Guid.NewGuid().ToString())
                    {
                        Expiration = Instrument.ExpirationTime(1)
                    };
                    Broker.CreatePendingOrder(trade);
                }
                {
                    var sign  = +1;
                    var ep    = Donchian[0, Top];
                    var tt    = CAlgo.SignToTradeType(sign);
                    var sl    = ep - sign * mcs * SLFrac;
                    var tp    = (QuoteCurrency?)null;
                    var vol   = Broker.ChooseVolume(Instrument, Math.Abs(ep - sl), risk: Risk);
                    var trade = new Trade(Instrument, tt, Label, ep, sl, tp, vol, comment: Guid.NewGuid().ToString())
                    {
                        Expiration = Instrument.ExpirationTime(1)
                    };
                    Broker.CreatePendingOrder(trade);
                }
                EntryCooldown = 1;
            }
        }
        /// <summary>Called when new data is received</summary>
        public override void Step()
        {
            base.Step();
            if (Instrument.NewCandle)
            {
                Dump();
            }

            var mcs             = Instrument.MCS;
            var price           = Instrument.LatestPrice;
            var trend_sign_slow = TrendSignSlow;
            var trend_sign_fast = TrendSignFast;

            // On a significantly extreme price level, buy/sell
            // For opening positions, use Bid when the price is high, Ask when the price is low.
            var sign = -ProbSign;
            var prob = Prob(sign);

            if (Math.Abs(prob) > OpenPositionProb)
            {
                // Todo:
                // The TrendSignFast is preventing trades being taken
                // If this worked it would offset the bad trades at MA crosses
                Dump();

                // Buy the lows, Sell the highs
                var ep   = Instrument.CurrentPrice(sign);
                var risk = Risk / 2;                 // Divide the risk amongst the number of positions that can be opened (1 in each direction)
                Debugging.Trace("Entry Trigger - {0} - prob={1:N3}".Fmt(sign > 0 ? "Buy" : "Sell", prob));
                Debugging.Trace(" FastTrend = {0}, SlowTrend = {1}".Fmt(trend_sign_fast, trend_sign_slow));

                for (;;)
                {
                    // Only allow one trade in each direction using this method
                    if (Positions.Count(x => x.Sign() == sign) != 0)
                    {
                        Debugging.Trace("  -Position with this sign already exists");
                        break;
                    }
                    Debugging.Trace("  +No existing {0} position".Fmt(sign));

                    // Only open positions in the direction of the trend
                    if (sign == -trend_sign_fast)
                    {
                        Debugging.Trace("  -Against the trend ({0})".Fmt(trend_sign_fast));
                        break;
                    }
                    Debugging.Trace("  +Not against the trend ({0} vs. {1})".Fmt(sign, trend_sign_fast));

                    // Don't open positions too close together
                    if (Broker.NearbyPositions(Label, ep, Instrument.MCS * MinTradeSeparation, sign))
                    {
                        Debugging.Trace("  -Nearby trades with the same sign ({0})".Fmt(sign));
                        break;
                    }
                    Debugging.Trace("  +No nearby trades with the same sign ({0})".Fmt(sign));

                    // Only open positions when the recent price has been heading in the direction we want to trade
                    var price_trend = Instrument.HighRes.FirstDerivative(-1) / Instrument.PipSize;
                    if (Math.Sign(price_trend) == -sign)
                    {
                        Debugging.Trace("  -Price trend ({0:N3}) against trade sign ({1})".Fmt(price_trend, sign));
                        break;
                    }
                    Debugging.Trace("  +Price trend ({0:N3} pips/tick) matches trade sign ({1})".Fmt(price_trend, sign));

                    // Don't open a position if the MA's look like they're about to cross
                    // in a direction that would make the trade against the trend.
                    var next_cross_idx = NextCrossIndex;
                    var ma_cross_sign  = MA0[0].CompareTo(MA1[0]);
                    if (next_cross_idx != null && next_cross_idx.Value < 2.5 && ma_cross_sign == sign)
                    {
                        Debugging.Trace("  -MA cross predicted in {0:N3} candles".Fmt(next_cross_idx.Value));
                        break;
                    }
                    Debugging.Trace("  +No MA cross from {0} to {1} predicted soon ({2})".Fmt(ma_cross_sign, -ma_cross_sign, next_cross_idx != null ? ((double)next_cross_idx.Value).ToString("N3") : ">5"));

                    // Choose a SL based on SnR levels and the slow MA
                    var rel = Math.Abs(ep - MA1[0]) + mcs;

                    // Create the positions
                    var tt    = CAlgo.SignToTradeType(sign);
                    var sl    = ep - sign * rel;
                    var tp    = ep + sign * rel * 1.5;
                    var vol   = Broker.ChooseVolume(Instrument, rel, risk: risk);
                    var trade = new Trade(Instrument, tt, Label, ep, sl, tp, vol, result: Trade.EResult.Open);
                    //Debugging.LogTrade(trade);
                    Broker.CreateOrder(trade);
                    break;
                }
            }
        }
Пример #7
0
        protected override void Step()
        {
            // Look for trade entry
            var sets_count = PositionSets.Count + PendingOrders.Count();

            if (sets_count < MaxPositionSets && EntryCooldown == 0)
            {
                var mcs        = Instrument.MCS;
                var price      = Instrument.LatestPrice;
                var trend_sign = Math.Sign(MA0[0].CompareTo(MA1[0]));

                for (;;)
                {
                    if (Math.Abs(MA1[0] - MA0[0]) < 0.5 * mcs)
                    {
                        break;
                    }

                    {
                        var sign  = trend_sign;
                        var ep    = MA1[0];
                        var tt    = CAlgo.SignToTradeType(sign);
                        var sl    = ep - sign * mcs * SLFrac;
                        var tp    = MA0[0];                     //(QuoteCurrency?)null;
                        var vol   = Broker.ChooseVolume(Instrument, Math.Abs(ep - sl), risk: Risk);
                        var trade = new Trade(Instrument, tt, Label, ep, sl, tp, vol)
                        {
                            Expiration = Instrument.ExpirationTime(1)
                        };
                        Broker.CreatePendingOrder(trade);
                        break;
                    }
                }

                //var dist_ask = MA0[0] - price.Ask;
                //var dist_bid = price.Bid - MA0[0];

                //var trend0 = ((Monic)MA0.Extrapolate(1, 5).Curve).A;
                //var trend1 = Instrument.EMASlope(0);
                //	//((Monic)MA1.Extrapolate(1, 5).Curve).A;

                //// Bias the price distance from the MA by the trend
                //dist_ask += trend0 * TrendWeight;
                //dist_bid -= trend0 * TrendWeight;

                //if (dist_ask > OpenDistance*mcs && Math.Sign(trend1) > 0)
                //{
                //	var sign = +1;
                //	var ep = price.Ask;
                //	var tt = TradeType.Buy;
                //	var sl = ep - sign * mcs * SLFrac;
                //	var tp = (QuoteCurrency?)null;
                //	var vol = Broker.ChooseVolume(Instrument, Math.Abs(ep - sl), risk:Risk);
                //	var trade = new Trade(Instrument, tt, Label, price.Ask, sl, tp, vol);
                //	Broker.CreateOrder(trade);
                //}
                //if (dist_bid > OpenDistance*mcs && Math.Sign(trend1) < 0)
                //{
                //	var sign = -1;
                //	var ep = price.Bid;
                //	var tt = TradeType.Sell;
                //	var sl = ep - sign * mcs * SLFrac;
                //	var tp = (QuoteCurrency?)null;
                //	var vol = Broker.ChooseVolume(Instrument, Math.Abs(ep - sl), risk:Risk);
                //	var trade = new Trade(Instrument, tt, Label, price.Bid, sl, tp, vol);
                //	Broker.CreateOrder(trade);
                //}
            }

            // Break point helper
            if (Instrument.NewCandle)
            {
                Dump();
            }
        }
        protected override void Step()
        {
            if (!Instrument.NewCandle)
            {
                return;
            }

            // Look for trade entry
            var sets_count = PositionSets.Count + PendingOrders.Count();

            if (sets_count < MaxPositionSets && EntryCooldown == 0)
            {
                // Wait for a Doji candle
                var mcs    = Instrument.MCS;
                var A      = Instrument[-1];
                var a_type = A.Type(mcs);
                if (!a_type.IsIndecision())
                {
                    return;
                }

                // Look for strong trade direction indications
                var trade_sign = (int?)null;
                for (;;)
                {
                    // Divergent extrapolation
                    var q0        = (Quadratic)MA0.Future.Curve;
                    var q1        = (Quadratic)MA1.Future.Curve;
                    var intersect = Maths.Intersection(q0, q1);
                    if (Math.Sign(q0.A) != Math.Sign(q1.A) || intersect.Length == 0)                    // || intersect.FirstOrDefault() >= 0)
                    {
                        break;
                    }

                    trade_sign = Math.Sign(q0.A);
                    break;
                }

                // Look for Marubozu followed by doji
                for (;;)
                {
                    // Find the preceding non-doji
                    var i      = -2;
                    var B      = Instrument[i];
                    var b_type = B.Type(mcs);
                    for (; i > Instrument.IdxFirst && b_type.IsIndecision(); --i, B = Instrument[i], b_type = B.Type(mcs))
                    {
                    }
                    if (!b_type.IsTrend())
                    {
                        break;
                    }

                    {
                        var sign = trade_sign ?? -B.Sign;
                        var ep   = A.Close;
                        var tt   = CAlgo.SignToTradeType(sign);
                        var sl   = ep - sign * mcs * SLFrac;
                        var tp   = ep + sign * mcs * SLFrac * 4;
                        //var tp = (QuoteCurrency?)null;
                        var vol   = Broker.ChooseVolume(Instrument, Math.Abs(ep - sl), risk: Risk);
                        var trade = new Trade(Instrument, tt, Label, ep, sl, tp, vol)
                        {
                            Expiration = Instrument.ExpirationTime(1)
                        };
                        Broker.CreateOrder(trade);
                        Debugging.Trace("  -Doji followed by Marubozu");
                        return;
                    }
                }

                // Look for a strong candle trend followed by a hammer or inverted hammer
                for (;;)
                {
                    // Get the candle trend leading up to 'A'
                    var candle_trend = Instrument.MeasureTrendFromCandles(-3, -1);
                    if (Math.Abs(candle_trend) < 0.8)
                    {
                        break;
                    }

                    // Look for a hammer pattern
                    if (a_type == Candle.EType.Hammer && Math.Sign(candle_trend) > 0)
                    {
                        break;
                    }
                    if (a_type == Candle.EType.InvHammer && Math.Sign(candle_trend) < 0)
                    {
                        break;
                    }

                    {
                        var sign = trade_sign ?? -Math.Sign(candle_trend);
                        var ep   = A.Close;
                        var tt   = CAlgo.SignToTradeType(sign);
                        var sl   = ep - sign * mcs * SLFrac;
                        var tp   = ep + sign * mcs * SLFrac * 4;
                        //var tp = (QuoteCurrency?)null;
                        var vol   = Broker.ChooseVolume(Instrument, Math.Abs(ep - sl), risk: Risk);
                        var trade = new Trade(Instrument, tt, Label, ep, sl, tp, vol)
                        {
                            Expiration = Instrument.ExpirationTime(1)
                        };
                        Broker.CreateOrder(trade);
                        Debugging.Trace("  -{0} pattern".Fmt(a_type));
                        return;
                    }
                }

                //var trend_sign = Math.Sign(MA0[0].CompareTo(MA1[0]));
                //var price_range = Instrument.PriceRange(i, 1).Inflate(1.05);
            }
        }
Пример #9
0
        /// <summary>Strategy step</summary>
        protected override void Step()
        {
            // MCS = 20-period EMA of the true range.
            // 1-Unit = Volume for a 1xMCS move equalling 1% equity
            // N-period break-out = the price exceeding the high or low of the last N periods.
            // N-period exit = the price making a new N-period low (for long positions) or high (for short positions)
            // System 1:
            //   Enter on 20-period break-out if the prior break-out was not a winner.
            //   Exit on 10-period break-out against the position.
            //   Open 1 unit at entry, and add 1 unit every 0.5*MCS above entry, move all stops to 2*MCS below
            var price = Instrument.LatestPrice;
            var mcs   = Instrument.MCS;

            var positions = Positions.ToArray();

            if (positions.Length == 0)
            {
                // System 1 - look for a short period breakout
                var tt = Instrument.IsBreakOut(System1_Entry);
                if (tt != null)
                {
                    var sign  = tt.Value.Sign();
                    var ep    = price.Price(sign);
                    var sl    = ep - sign * mcs * StopLossFrac;
                    var vol   = Broker.ChooseVolume(Instrument, 1 * mcs, risk: 1.0 / MaxPositions);
                    var trade = new Trade(Instrument, tt.Value, Label, ep, sl, null, vol);

                    // Enter if the last breakout was not a winner
                    //	var last = BreakoutsHistory.LastOrDefault();
                    //	if (last == null || last.NetProfit < 0)
                    {
                        Dump();

                        Broker.CreateOrder(trade);
                        ActiveBreakout = trade;
                    }
                    //	else if (ActiveBreakout == null)
                    //	{
                    //		Dump();
                    //
                    //		// Save each breakout, so we can tell if they are winners
                    //		ActiveBreakout = trade;
                    //	}
                }
            }

            // Look to increase the position size
            else if (positions.Length > 0 && positions.Length < MaxPositions)
            {
                var sign = positions[0].Sign();

                // Get the initial entry price
                var initial_ep = sign > 0 ? positions.Min(x => x.EntryPrice) : positions.Max(x => x.EntryPrice);

                // Get the level the price needs to have crossed
                var ep = initial_ep + sign * positions.Length * mcs * AddPositionFrac;

                // Add to the position every AddPositionFrac*N gain
                if (Math.Sign(Instrument.LatestPrice.Price(sign) - ep) == sign)
                {
                    Dump();

                    var sl  = ep - sign * mcs * StopLossFrac;
                    var vol = Broker.ChooseVolume(Instrument, 1 * mcs, risk: 1.0 / MaxPositions);

                    // Adjust the SL on existing trades
                    foreach (var pos in positions)
                    {
                        Broker.ModifyOrder(Instrument, pos, sl: pos.StopLoss + sign * mcs * AddPositionFrac);
                    }

                    // Add to the position
                    var trade = new Trade(Instrument, CAlgo.SignToTradeType(sign), Label, ep, sl, null, vol);
                    Broker.CreateOrder(trade);
                }
            }

            // Simulate each active 'trade'
            if (ActiveBreakout != null)
            {
                ActiveBreakout.Simulate(Instrument.LatestPrice);

                // Look for exits on the simulated trade
                var exit_tt = Instrument.IsBreakOut(System1_Exit);
                if (exit_tt != null && ActiveBreakout.TradeType != exit_tt.Value)
                {
                    Dump();

                    // Close any trades where 'exit_tt' is opposes the trade direction
                    ActiveBreakout.Close();
                    BreakoutsHistory.Add(ActiveBreakout);
                    ActiveBreakout = null;
                }
            }
        }
Пример #10
0
        protected override void Step()
        {
            // Look for trade entry
            var sets_count = PositionSets.Count + PendingOrders.Count();

            if (sets_count < MaxPositionSets && EntryCooldown == 0)
            {
                // Wait for a sequence of candles entirely above or below the MA
                var price = Instrument.LatestPrice;
                var mcs   = Instrument.MCS;

                // Look for a sequence of candles that are entirely above or below the MA
                var bulge = FindBulges(0, MA0).FirstOrDefault();
                if (bulge.Sign != 0 && Instrument.IdxLast - bulge.Range.End <= NonIntersectingCount)
                {
                    Debugging.AreaOfInterest(bulge.Range, append: false);

                    // Decide the direction
                    int sign = 0;

                    //// Trade in the direction of the slow MA if it is trending strongly
                    //var ma_slope = MA1.FirstDerivative(0) / Instrument.PipSize;
                    //if (Math.Abs(ma_slope) > MATrendSlope)
                    //{
                    //	sign = Math.Sign(ma_slope);
                    //}
                    //else
                    {
                        // Using measured stats of bulge sequences, the probabilities are:
                        // 0 = below the MA, 1 = above the MA
                        var next_bulge_sign = new []
                        {
                            -1,                             //  000: -0.168091168091168 (count=351)
                            +1,                             //  001:  0.224489795918367 (count=245)
                            -1,                             //  010: -0.069767441860465 (count=172)
                            +1,                             //  011:  0.158730158730159 (count=252)
                            -1,                             //  100: -0.195121951219512 (count=246)
                            +1,                             //  101:  0.139664804469274 (count=179)
                            -1,                             //  110: -0.217391304347826 (count=253)
                            +1,                             //  111:  0.064102564102564 (count=312)
                        };

                        // Include the current bulge because the trade triggers when this bulge closes
                        var bulge_signs = new List <int>();
                        FindBulges(0, MA0).Take(3).ForEach(b => bulge_signs.Insert(0, b.Sign));                         // Careful with order
                        sign = next_bulge_sign[Bit.SignsToIndex(bulge_signs)];
                    }

                    {                    // Create a pending order
                        var ep    = MA0[0];
                        var tt    = CAlgo.SignToTradeType(sign);
                        var sl    = ep - sign * mcs * SLFrac;                      // Note: the SL needs to be big enough that a paired order is triggered before this trade is closed
                        var tp    = (QuoteCurrency?)null;
                        var vol   = Broker.ChooseVolume(Instrument, Math.Abs(ep - sl), risk: Risk);
                        var trade = new Trade(Instrument, tt, Label, ep, sl, tp, vol, comment: Guid.NewGuid().ToString())
                        {
                            Expiration = Instrument.ExpirationTime(1)
                        };
                        Broker.CreatePendingOrder(trade);
                    }

                    EntryCooldown = 1;
                }
            }

            // Increase position size on winning positions
            //IncreasePosition();

            // Break point helper
            if (Instrument.NewCandle)
            {
                Dump();
            }
        }
Пример #11
0
        /// <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;
                }
            }
        }