Esempio n. 1
0
        internal static Optional <ITrade> AttemptTrade(IEnumerable <BidAskCandle> candles, double entry, double stop,
                                                       double target, TimeSpan startTime, TimeSpan endTime, double risk, bool trialStop, double trialedStopSize)
        {
            var    executed     = false;
            var    openTime     = DateTime.MaxValue;
            var    lastCandle   = new BidAskCandle(new DateTime(1, 1, 1), 1, 1, 1, 1, 1, Timezone.Uk);
            double openLevel    = 0;
            var    stopSize     = Math.Abs(entry - stop);
            var    positionSize = risk / stopSize;
            var    direction    = target > stop ? TradeDirection.Long : TradeDirection.Short;

            var high = double.NegativeInfinity;
            var low  = double.PositiveInfinity;

            var originalStop               = stop;
            var maximumAdverseExcursion    = 0.0;
            var maximumFavourableExcursion = 0.0;

            var stopTrailed = false;

            foreach (var candle in candles)
            {
                if (candle.DateTime.TimeOfDay >= startTime && candle.DateTime.TimeOfDay <= endTime)
                {
                    if (direction == TradeDirection.Long)
                    {
                        if (trialStop && executed)
                        {
                            if (candle.BidOpen > high)
                            {
                                high = candle.BidOpen;
                            }

                            // Trail stop only if in profit by at least the size of the trailed stop
                            if (high > stop + trialedStopSize && high > openLevel + trialedStopSize)
                            {
                                stop        = candle.BidOpen - trialedStopSize;
                                stopTrailed = true;
                            }
                        }

                        // When not starting at the first candle of the day,
                        // if the first candle opens past the initial intended entry (positive slippage),
                        // enter the trade on the open of that candle and update stop level accordingly
                        if (candle.AskOpen <= entry && !executed)
                        {
                            openLevel    = candle.AskOpen;
                            stop         = openLevel - stopSize;
                            originalStop = openLevel - stopSize;
                            executed     = true;
                            openTime     = candle.DateTime;
                        }

                        if (candle.AskLow < entry && !executed)
                        {
                            openLevel = entry;
                            executed  = true;
                            openTime  = candle.DateTime;
                        }

                        if (executed)
                        {
                            var adverseExcursion = openLevel - candle.AskLow;

                            if (adverseExcursion > maximumAdverseExcursion)
                            {
                                maximumAdverseExcursion = adverseExcursion;
                            }

                            var favourableExcursion = candle.BidHigh - openLevel;

                            if (favourableExcursion > maximumAdverseExcursion)
                            {
                                maximumFavourableExcursion = favourableExcursion;
                            }

                            // Ensure MFA is 100% if target is hit
                            if (candle.BidHigh > target)
                            {
                                maximumFavourableExcursion = target - openLevel;
                            }
                        }

                        if (candle.BidLow < stop && executed)
                        {
                            // Ensure MAE is 100% if full original stop is hit
                            if (!stopTrailed)
                            {
                                maximumAdverseExcursion = stopSize;
                            }

                            return(Option.Some((ITrade) new Trade(entry, originalStop, target, openLevel, Option.Some(stop), openTime, Option.Some(candle.DateTime), positionSize, Option.Some(maximumAdverseExcursion), Option.Some(maximumFavourableExcursion))));
                        }

                        if (candle.BidHigh > target && executed)
                        {
                            return(Option.Some((ITrade) new Trade(entry, originalStop, target, openLevel, Option.Some(target), openTime, Option.Some(candle.DateTime), positionSize, Option.Some(maximumAdverseExcursion), Option.Some(maximumFavourableExcursion))));
                        }
                    }
                    else if (direction == TradeDirection.Short)
                    {
                        if (trialStop && executed)
                        {
                            if (candle.AskOpen < low)
                            {
                                low = candle.AskOpen;
                            }

                            if (low < stop - trialedStopSize && low < openLevel - trialedStopSize)
                            {
                                stop        = candle.AskOpen + trialedStopSize;
                                stopTrailed = true;
                            }
                        }

                        // See above comment on opposite direction trade
                        if (candle.BidOpen >= entry && !executed)
                        {
                            openLevel    = candle.BidOpen;
                            stop         = openLevel + stopSize;
                            originalStop = openLevel + stopSize;
                            executed     = true;
                            openTime     = candle.DateTime;
                        }

                        if (candle.BidHigh > entry && !executed)
                        {
                            openLevel = entry;
                            executed  = true;
                            openTime  = candle.DateTime;
                        }

                        if (executed)
                        {
                            var adverseExcursion = candle.BidHigh - openLevel;

                            if (adverseExcursion > maximumAdverseExcursion)
                            {
                                maximumAdverseExcursion = adverseExcursion;
                            }

                            var favourableExcursion = openLevel - candle.AskLow;

                            if (favourableExcursion > maximumAdverseExcursion)
                            {
                                maximumFavourableExcursion = favourableExcursion;
                            }

                            // Ensure MFA is 100% if target is hit
                            if (candle.AskLow < target)
                            {
                                maximumFavourableExcursion = openLevel - target;
                            }
                        }

                        if (candle.AskHigh > stop && executed)
                        {
                            // Ensure MAE is 100% if full original stop is hit
                            if (!stopTrailed)
                            {
                                maximumAdverseExcursion = stopSize;
                            }

                            return(Option.Some((ITrade) new Trade(entry, originalStop, target, openLevel, Option.Some(stop), openTime, Option.Some(candle.DateTime), positionSize, Option.Some(maximumAdverseExcursion), Option.Some(maximumFavourableExcursion))));
                        }

                        if (candle.AskLow < target && executed)
                        {
                            return(Option.Some((ITrade) new Trade(entry, originalStop, target, openLevel, Option.Some(target), openTime, Option.Some(candle.DateTime), positionSize, Option.Some(maximumAdverseExcursion), Option.Some(maximumFavourableExcursion))));
                        }
                    }

                    lastCandle = candle;
                }
            }

            if (!executed)
            {
                return(Option.None <ITrade>());
            }

            // When trade is executed but neither stop or target is hit close trade at close level of last candle
            double close;

            close = direction == TradeDirection.Long ? lastCandle.BidClose : lastCandle.AskClose;

            return(Option.Some((ITrade) new Trade(entry, originalStop, target, entry, Option.Some(close), openTime, Option.Some(lastCandle.DateTime), positionSize, Option.Some(maximumAdverseExcursion), Option.Some(maximumFavourableExcursion))));
        }
Esempio n. 2
0
        internal static Optional <ITrade> AttemptTrade(IEnumerable <BidAskCandle> candles, double entry, double stop,
                                                       double target, TimeSpan startTime, TimeSpan endTime, double risk)
        {
            var    executed     = false;
            var    openTime     = DateTime.MaxValue;
            var    lastCandle   = new BidAskCandle(new DateTime(1, 1, 1), 1, 1, 1, 1, 1, Timezone.Uk);
            double openLevel    = 0;
            var    stopSize     = Math.Abs(entry - stop);
            var    positionSize = risk / stopSize;
            var    direction    = target > stop ? TradeDirection.Long : TradeDirection.Short;

            foreach (var candle in candles)
            {
                if (candle.DateTime.TimeOfDay >= startTime && candle.DateTime.TimeOfDay <= endTime)
                {
                    if (direction == TradeDirection.Long)
                    {
                        // When not starting at the first candle of the day,
                        // if the first candle opens past the initial intended entry (positive slippage),
                        // enter the trade on the open of that candle and update stop level accordingly
                        if (candle.AskOpen <= entry && !executed)
                        {
                            openLevel = candle.AskOpen;
                            stop      = entry - stopSize;
                            executed  = true;
                            openTime  = candle.DateTime;
                        }

                        if (candle.AskLow < entry && !executed)
                        {
                            openLevel = entry;
                            executed  = true;
                            openTime  = candle.DateTime;
                        }

                        if (candle.BidLow < stop && executed)
                        {
                            return(Option.Some((ITrade) new Trade(entry, stop, target, openLevel, Option.Some(stop), openTime, Option.Some(candle.DateTime), positionSize)));
                        }

                        if (candle.BidHigh > target && executed)
                        {
                            return(Option.Some((ITrade) new Trade(entry, stop, target, openLevel, Option.Some(target), openTime, Option.Some(candle.DateTime), positionSize)));
                        }
                    }
                    else if (direction == TradeDirection.Short)
                    {
                        // See above comment on opposite direction trade
                        if (candle.BidOpen >= entry && !executed)
                        {
                            openLevel = candle.BidOpen;
                            stop      = openLevel + stopSize;
                            executed  = true;
                            openTime  = candle.DateTime;
                        }

                        if (candle.BidHigh > entry && !executed)
                        {
                            openLevel = entry;
                            executed  = true;
                            openTime  = candle.DateTime;
                        }

                        if (candle.AskHigh > stop && executed)
                        {
                            return(Option.Some((ITrade) new Trade(entry, stop, target, openLevel, Option.Some(stop), openTime, Option.Some(candle.DateTime), positionSize)));
                        }

                        if (candle.AskLow < target && executed)
                        {
                            return(Option.Some((ITrade) new Trade(entry, stop, target, openLevel, Option.Some(target), openTime, Option.Some(candle.DateTime), positionSize)));
                        }
                    }

                    lastCandle = candle;
                }
            }

            if (!executed)
            {
                return(Option.None <ITrade>());
            }

            // When trade is executed but neither stop or target is hit close trade at close level of last candle
            var close = direction == TradeDirection.Long ? lastCandle.BidClose : lastCandle.AskClose;

            return(Option.Some((ITrade) new Trade(entry, stop, target, entry, Option.Some(close), openTime, Option.Some(lastCandle.DateTime), positionSize)));
        }