public void Setup()
        {
            tradeRepositoryMock = new Mock <ITradeRepository>();
            var now = new DateTime(2017, 2, 17, 22, 22, 34);
            var dateTimeProvider = new Mock <IDateTimeProvider>();

            dateTimeProvider.Setup(x => x.Now).Returns(now);

            tradeCalculator = new TradeCalculator(tradeRepositoryMock.Object, dateTimeProvider.Object);
            teaStock        = new CommonStock {
                StockSymbol = "TEA"
            };
            ginStock = new CommonStock {
                StockSymbol = "GIN"
            };
            aleStock = new CommonStock {
                StockSymbol = "ALE"
            };
        }
Esempio n. 2
0
        public static void AddLimitPrice(this Trade trade, string id, DateTime date, decimal?price)
        {
            if (trade.LimitPrices.Count > 0 && trade.LimitPrices.Last().Price == price)
            {
                return;
            }

            if (trade.LimitPrices.Count > 0 && trade.LimitPrices.Last().Date == date)
            {
                trade.LimitPrices.RemoveAt(trade.OrderPrices.Count - 1);
            }

            if (trade.UpdateMode == TradeUpdateMode.Unchanging)
            {
                throw new ApplicationException("Trade set to untouched mode cannot change it's limit price after being set");
            }

            trade.LimitPrices.Add(new DatePrice(id, date, price));

            if (trade.LimitPrices.Count > 1)
            {
                trade.LimitPrices = trade.LimitPrices.OrderBy(x => x.Date).ToList();
            }

            TradeCalculator.UpdateLimit(trade);

            if (!trade.CalculateOptions.HasFlag(CalculateOptions.ExcludePipsCalculations))
            {
                TradeCalculator.UpdateLimitPips(trade);

                if (trade.LimitPrices.Count == 1)
                {
                    TradeCalculator.UpdateInitialLimitPips(trade);
                }
            }
        }
Esempio n. 3
0
        public List <Trade> Run(StrategyBase strategy, Func <bool> getShouldStopFunc, DateTime?startTime = null, DateTime?endTime = null)
        {
            var logIntervalSeconds          = 5;
            var candleTimeframes            = strategy.Timeframes;
            var smallestNonM1Timeframe      = candleTimeframes.First();
            var candleTimeframesExcSmallest = candleTimeframes.Where(x => x != smallestNonM1Timeframe).ToList();
            var m1Candles              = _candleService.GetCandles(_broker, _market.Name, Timeframe.M1, false);
            var allCandles             = GetCandles(candleTimeframes);
            var timeframeCandleIndexes = new TimeframeLookup <int>();
            var currentCandles         = new TimeframeLookup <List <Candle> >();
            var trades      = new TradeWithIndexingCollection();
            var nextLogTime = DateTime.UtcNow.AddSeconds(logIntervalSeconds);
            var calls       = 0;

            strategy.SetSimulationParameters(trades, currentCandles, _market);

            foreach (var tf in candleTimeframes)
            {
                currentCandles[tf] = new List <Candle>(10000);
            }
            var smallestNonM1TimeframeCount = allCandles[smallestNonM1Timeframe].Count;

            var m1CandleIndex = 0;

            Candle smallestNonM1Candle;

            var startTimeTicks = startTime != null ? (long?)startTime.Value.Ticks : null;
            var endTimeTicks   = endTime != null ? (long?)endTime.Value.Ticks : null;

            strategy.SetInitialised();

            // Ignore M1 candles
            for (var smallestNonM1TfIndex = 0;
                 smallestNonM1TfIndex < smallestNonM1TimeframeCount;
                 smallestNonM1TfIndex++)
            {
                if (getShouldStopFunc != null && getShouldStopFunc())
                {
                    return(null);
                }

                // Progress smallest non-M1 candle
                smallestNonM1Candle = allCandles[smallestNonM1Timeframe][smallestNonM1TfIndex];
                currentCandles[smallestNonM1Timeframe].Add(smallestNonM1Candle);
                var newCandleTimeframes = new List <Timeframe> {
                    smallestNonM1Timeframe
                };

                if (DateTime.UtcNow > nextLogTime)
                {
                    LogProgress(trades, smallestNonM1Candle.CloseTimeTicks);
                    nextLogTime = DateTime.UtcNow.AddSeconds(logIntervalSeconds);
                }

                // Progress other timeframes
                foreach (var tf in candleTimeframesExcSmallest)
                {
                    for (var i = timeframeCandleIndexes[tf]; i < allCandles[tf].Count; i++)
                    {
                        var c = allCandles[tf][i];
                        if (c.CloseTimeTicks <= smallestNonM1Candle.CloseTimeTicks)
                        {
                            currentCandles[tf].Add(c);
                            newCandleTimeframes.Add(tf);
                            timeframeCandleIndexes[tf] = i + 1;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                // Process M1 candles if any trades are open or and orders
                if ((trades.AnyOpen || trades.AnyOrders) && m1CandleIndex < m1Candles.Count)
                {
                    // Include M1 candles
                    var nextIndex = m1Candles.BinarySearchGetItem(
                        i => m1Candles[i].CloseTimeTicks,
                        m1CandleIndex,
                        smallestNonM1TfIndex > 0 ? allCandles[smallestNonM1Timeframe][smallestNonM1TfIndex - 1].CloseTimeTicks : smallestNonM1Candle.OpenTimeTicks,
                        BinarySearchMethod.NextHigherValue);

                    if (nextIndex != -1 && m1Candles[nextIndex].CloseTimeTicks <= m1Candles[m1CandleIndex].CloseTimeTicks)
                    {
                        throw new ApplicationException("M1 candles are not running in order");
                    }

                    if (nextIndex != -1 && m1Candles[nextIndex].CloseTimeTicks <= smallestNonM1Candle.CloseTimeTicks)
                    {
                        m1CandleIndex = nextIndex;

                        for (var i = m1CandleIndex; i < m1Candles.Count; i++)
                        {
                            var m1 = m1Candles[i];
                            if (m1.CloseTimeTicks > smallestNonM1Candle.CloseTimeTicks)
                            {
                                break;
                            }

                            m1CandleIndex = i;
                            if (!trades.AnyOpen && !trades.AnyOrders)
                            {
                                break;
                            }

                            if (trades.AnyOrders)
                            {
                                FillOrders(trades, m1);
                            }
                            if (trades.AnyOpen)
                            {
                                TryCloseOpenTrades(trades, m1);
                                calls++;
                            }
                        }
                    }
                }

                // Process new completed candles in strategy
                try
                {
                    strategy.UpdateIndicators(newCandleTimeframes);
                    strategy.NewTrades.Clear();

                    if (startTimeTicks == null || (smallestNonM1Candle.CloseTimeTicks >= startTimeTicks && smallestNonM1Candle.CloseTimeTicks <= endTimeTicks))
                    {
                        strategy.ProcessCandles(newCandleTimeframes);
                    }
                }
                catch (Exception ex)
                {
                    Log.Error("Error processing new candles", ex);
                    return(null);
                }

                RemoveInvalidTrades(strategy.NewTrades, smallestNonM1Candle.CloseBid, smallestNonM1Candle.CloseAsk);

                // Add new trades
                foreach (var t in strategy.NewTrades)
                {
                    if (t.CloseDateTime != null)
                    {
                        trades.AddClosedTrade(t);
                    }
                    else if (t.EntryDateTime == null && t.OrderDateTime != null)
                    {
                        trades.AddOrderTrade(t);
                    }
                    else if (t.EntryDateTime != null)
                    {
                        trades.AddOpenTrade(t);
                    }
                }
            }

            LogProgress(trades, allCandles[smallestNonM1Timeframe][allCandles[smallestNonM1Timeframe].Count - 1].CloseTimeTicks);

            var ret = trades.AllTrades.Select(x => x.Trade).ToList();

            foreach (var t in ret)
            {
                TradeCalculator.UpdateInitialStopPips(t);
                TradeCalculator.UpdateInitialLimitPips(t);
                TradeCalculator.UpdateRMultiple(t);
            }

            return(ret);
        }