Exemple #1
0
        // Notes:
        // Determine the SnR levels within the given price range
        // - ignore candles that aren't within the range.

        /// <summary>Find support and resistance level data within the given price range</summary>
        /// <param name="instrument">The instrument to find levels data in</param>
        /// <param name="iend">The last candle, i.e. look backwards from here</param>
        /// <param name="price">The centre price to centre the SnR level data around</param>
        /// <param name="count">The number of candles that contribute to the SnR levels (only candles intersecting the range)</param>
        /// <param name="range">The range of prices (above and below 'price') to check</param>
        public SnR(Instrument instrument, QuoteCurrency?price = null, Idx?iend = null, int?count = null, QuoteCurrency?range = null, TimeFrame tf = null, QuoteCurrency?bucket_size = null)
        {
            price = price ?? instrument.LatestPrice.Mid;
            iend  = iend ?? 1;

            // Set the range based on the recent span of candles
            if (range == null)
            {
                // Use a minimum of 5*MCS
                var r = instrument.MCS * 5;
                foreach (var c in instrument.CandleRange(iend.Value - 200, iend.Value))
                {
                    r = Math.Max(r, Math.Abs(c.High - price.Value));
                    r = Math.Max(r, Math.Abs(price.Value - c.Low));
                }
                range = r;
            }
            ;

            SnRLevels  = new List <Level>();
            Instrument = instrument;
            Beg        = iend.Value;
            End        = iend.Value;
            Count      = count ?? instrument.Bot.Settings.SnRHistoryLength;
            Range      = range.Value;
            Price      = price.Value;
            BucketSize = bucket_size ?? instrument.PipSize * 3;            //instrument.MCS;
            TimeFrame  = tf ?? Instrument.TimeFrame.GetRelativeTimeFrame(16);

            CalculateLevels();
        }
Exemple #2
0
        /// <summary>True if a break-out to the 'high' side is detected</summary>
        private bool IsBreakOutInternal(Monic trend, List <Peak> peaks, bool high)
        {
            // A break-out is when the latest candle is significantly above the upper trend line
            // or below the lower trend line and showing signs of going further. Also, the preceding candles
            // must be below the trend line.

            // No trend, no break-out
            if (trend == null)
            {
                return(false);
            }

            // The latest candle must be in the break-out direction
            var sign   = high ? +1 : -1;
            var latest = Instrument.Latest;

            if (latest.Sign != sign)
            {
                return(false);
            }

            // The price must be beyond the trend by a significant amount
            var price_threshold = trend.F(0.0) + sign * Instrument.MCS;

            if (Math.Sign(latest.Close - price_threshold) != sign)
            {
                return(false);
            }

            // Only the latest few candles can be beyond the trend line
            // and all must be in the direction of the break out.
            if (peaks[0].Index < -2)
            {
                // Allow the last two candles to be part of the break out
                foreach (var c in Instrument.CandleRange(peaks[0].Index, -2))
                {
                    // If more than half the candle is beyond the trend line, not a breakout
                    var ratio = sign * Instrument.Compare(c, trend, false);
                    if (ratio > 0)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
Exemple #3
0
        /// <summary>Determine a measure of trend strength</summary>
        private double TrendStrength(Monic trend, List <Peak> peaks, bool high)
        {
            if (trend == null)
            {
                return(0.0);
            }

            // Trend strength has to be a measure of how often price approached the trend line
            // and bounced off. Candles miles away from the trend line don't count, only consider
            // candles that span or are within a tolerance range of the trend line.
            var above = 0.0; var below = 0.0; var count = 0;
            var threshold = ConfirmTrend * Instrument.MCS;

            foreach (var c in Instrument.CandleRange(peaks.Back().Index, Instrument.IdxLast - WindowSize))
            {
                var p = trend.F(c.Index + Instrument.IdxFirst);
                if (c.High < p - threshold)
                {
                    continue;
                }
                if (c.Low > p + threshold)
                {
                    continue;
                }
                above += Math.Max(0, c.High - p);
                below += Math.Max(0, p - c.Low);
                ++count;
            }

            // There must be some candles contributing
            var total = above + below;

            if (total == 0)
            {
                return(0.0);
            }

            // Return the proportion of above to below
            var strength = (high ? +1 : -1) * (below - above) / total;

            // Weight the strength based on the number of candles that contribute
            var weighted_count = Maths.Sigmoid(count, 6);

            return(strength * weighted_count);
        }
Exemple #4
0
        /// <summary>Manage an open trade. This should be called on each tick</summary>
        protected override void StepCore()
        {
            // Move SL to break even when profit > BreakEvenThreshold (adjusted for Spread)
            var adjusted_profit = Position.NetProfit - Instrument.Symbol.QuoteToAcct(Instrument.Spread * Position.Volume);

            if (adjusted_profit > BreakEvenThreshold && Position.StopLossRel() > 0)
            {
                Bot.Debugging.Trace("Moving SL to break even - Profit ${0} > Threshold ${1}".Fmt(Position.NetProfit, BreakEvenThreshold));

                var trade = new Trade(Instrument, Position)
                {
                    SL = Position.EntryPrice + Position.Sign() * 2.0 * Instrument.Spread
                };
                Broker.ModifyOrder(Position, trade);
            }

            // What about candle follow mode:
            // If the price is heading for the TP and the last tops/bottoms of the last few candles
            // have been steadily increasing/decreasing. Move the SL to just above/below the previous candle

            // A state machine for managing the position
            switch (State)
            {
            // In this state, the trade looks good. Keep it open.
            case EState.TradeLooksGood:
                #region
            {
                // Enter scalp mode when profit > scalp threshold
                if (Profit > ScalpThreshold)
                {
                    Bot.Debugging.Trace("Entering scalp mode - Profit ${0} > Threshold ${1}".Fmt(Profit, ScalpThreshold));
                    State = EState.Scalp;
                }
                else if (CandlesSincePeak >= ColdFeetCount)
                {
                    // It's been a while since a profit peak was set...
                    Bot.Debugging.Trace("Getting nervous... no peaks for a while");
                    State = EState.LookForExitAfterNextPeak;
                }
                break;
            }

                #endregion
            case EState.Scalp:
            {
                // In this mode we've made a decent profit.
                var close = false;
                for (;;)
                {
                    //// Close if the profit drops to fraction of the peak
                    //const double ScalpFraction = 0.5;
                    //if (Position.NetProfit < ScalpFraction * PeakProfit)
                    //{
                    //	close = true;
                    //	Debugging.Trace("Position closed - profit dropped by {0} - ${1}".Fmt(ScalpFraction, Position.NetProfit));
                    //}

                    // Close if the closed candle is an indecision candle.
                    if (Instrument.NewCandle &&
                        Instrument[-1].Type(Instrument.MCS).IsIndecision())
                    {
                        Bot.Debugging.Trace("Closing position - indecision candle");
                        close = true;
                        break;
                    }

                    // Close if the peak of the candle just closed is not better than the candle before's peak i.e. Not higher lows, or lower highs
                    if (Instrument.NewCandle &&
                        Position.EntryTime < Instrument[-1].TimestampUTC &&
                        Instrument.SequentialPeaks(Position.Sign(), 0) < 1)
                    {
                        Bot.Debugging.Trace("Closing position - peaks oppose trend direction");
                        close = true;
                        break;
                    }

                    // Close if the candle closes worse then the close of the -2 candle
                    if (Instrument.NewCandle &&
                        Position.EntryTime < Instrument[-1].TimestampUTC &&
                        Math.Sign(Instrument[-1].Close - Instrument[-2].Close) != Position.Sign())
                    {
                        Bot.Debugging.Trace("Closing position - candle close was worse that close of -2 candle");
                        close = true;
                        break;
                    }

                    // Close if the profit is huge
                    if (Position.NetProfit > 2.0 * ScalpThreshold && TicksSincePeak > 10)
                    {
                        Bot.Debugging.Trace("Closing position - huge spike detected!");
                        close = true;
                        break;
                    }

                    // Don't close.
                    break;
                }
                if (close)
                {
                    Broker.ClosePosition(Position, "{0} - Scalp".Fmt(R <PositionManagerNervious> .NameOf));
                    State = EState.PositionClosed;
                }
                break;
            }

            case EState.TrailingSL:
            {
                // In this mode, we move the SL up to just above/below a recently closed candle
                if (Instrument.NewCandle)
                {
                    var sign  = Position.TradeType.Sign();
                    var limit = Instrument.CurrentPrice(-sign);
                    foreach (var c in Instrument.CandleRange(-3, 0))
                    {
                        limit = sign > 0 ? Math.Min(limit, c.Low) : Math.Max(limit, c.High);
                    }

                    // Move the SL if in the correct direction
                    if (sign > 0 && limit > Position.StopLoss ||
                        sign < 0 && limit < Position.StopLoss)
                    {
                        var trade = new Trade(Instrument, Position)
                        {
                            SL = limit
                        };
                        Broker.ModifyOrder(Position, trade);
                    }
                }
                break;
            }

            case EState.LookForExitAfterNextPeak:
            {
                // In this state, the profit hit a peak a while ago,
                // and we're waiting for it to come back to that peak
                // level so we can bail out.
                if (NewPeak)
                {
                    State = EState.CloseAtNextNonPeak;
                    Bot.Debugging.Trace("Closing at next non peak");
                }
                else if (CandlesSincePeak >= 2 * ColdFeetCount)
                {
                    State = EState.BailIfProfitable;
                    Bot.Debugging.Trace("Closing when profitable");
                }
                break;
            }

            case EState.CloseAtNextNonPeak:
            {
                // In this state we're looking to exit the trade the
                // next time the profit peak is not set
                if (!NewPeak)
                {
                    Broker.ClosePosition(Position, "{0} - Non-Peak".Fmt(R <PositionManagerNervious> .NameOf));
                    State = EState.PositionClosed;
                    Bot.Debugging.Trace("Position closed - non-peak");
                }
                break;
            }

            case EState.CloseAtNextProfitDrop:
            {
                // In this state we just want out with the minimum of loss.
                // Bail as soon as the profit decreases
                if (!IsGain)
                {
                    Broker.ClosePosition(Position, "{0} - Next Profit Drop".Fmt(R <PositionManagerNervious> .NameOf));
                    State = EState.PositionClosed;
                    Bot.Debugging.Trace("Position closed - profit dropped");
                }
                break;
            }

            case EState.BailIfProfitable:
            {
                // In this state, it's been too long since the peak was last
                // hit, bail out if profitable
                if (NewPeak)
                {
                    State = EState.CloseAtNextNonPeak;
                }
                else if (Position.NetProfit > 0)
                {
                    Broker.ClosePosition(Position, "{0} - Bail With Profit".Fmt(R <PositionManagerNervious> .NameOf));
                    State = EState.PositionClosed;
                }
                else if (CandlesSinceProfitable > 4 * ColdFeetCount)
                {
                    State = EState.CloseAtNextProfitDrop;
                    Bot.Debugging.Trace("Closing at next drop in profit");
                }
                break;
            }
            }
        }