public RunStrategyLiveViewModel() { DependencyContainer.ComposeParts(this); RunLiveCommand = new DelegateCommand(o => RunLive()); _fxcm = (FxcmBroker)_brokersService.Brokers.First(x => x.Name == "FXCM"); _strategiesDirectory = _dataDirectoryService.MainDirectoryWithApplicationName; _logDirectory = DataDirectoryService.GetMainDirectoryWithApplicationName("FXCMTradeLog"); _brokersService.LoadBrokerAccounts(_tradeDetailsAutoCalculatorService, _logDirectory); _brokerAccount = _brokersService.AccountsLookup[_fxcm]; }
private void RunLive(string selectedStrategyFilename) { var trades = new TradeWithIndexingCollection(); var strategyLookup = new Dictionary <string, StrategyBase>(); var candlesLookup = new Dictionary <string, TimeframeLookup <List <Candle> > >(); var accountSaveIntervalSeconds = 60; var accountLastSaveTime = DateTime.UtcNow; Log.Info("Running live"); // Get strategy type and markets var strategyType = CompileStrategyAndGetStrategyMarkets(selectedStrategyFilename, out var markets, out var timeframes); if (strategyType == null) { return; } // Update broker account Log.Info("Updating broker account"); _brokerAccount.UpdateBrokerAccount(_fxcm, _candlesService, _marketDetailsService, _tradeDetailsAutoCalculatorService, UpdateOption.ForceUpdate); // Get candles Log.Info("Getting candles"); foreach (var m in markets) { candlesLookup[m] = new TimeframeLookup <List <Candle> >(); foreach (var t in timeframes) { candlesLookup[m].Add(t, _candlesService.GetCandles(_fxcm, m, t, true, forceUpdate: true, cacheData: true)); } } // Setup locks foreach (var market in markets) { _marketLock[market] = new object(); } // Create strategies Log.Info("Setting up strategies"); foreach (var market in markets) { var strategy = (StrategyBase)Activator.CreateInstance(strategyType); var currentCandles = new TimeframeLookup <List <Candle> >(); strategy.SetSimulationParameters(trades, currentCandles, _marketDetailsService.GetMarketDetails("FXCM", market)); strategyLookup.Add(market, strategy); // Setup candles for strategy foreach (var t in timeframes) { currentCandles.Add(t, candlesLookup[market][t].Where(c => c.IsComplete == 1).ToList()); } } // Get live prices steams var priceMonitor = new MonitorLivePrices(_fxcm, p => ProcessNewPrice(markets, timeframes, p, candlesLookup)); try { var checkFxcmConnectedIntervalSeconds = 60 * 5; var nextFxcmConnectedCheckTime = DateTime.UtcNow.AddSeconds(checkFxcmConnectedIntervalSeconds); Log.Info("Running main processing loop"); while (true) { if (accountLastSaveTime < DateTime.UtcNow.AddSeconds(-accountSaveIntervalSeconds)) { lock (_brokerAccount) { Log.Debug("Saving broker account"); _brokerAccount.SaveAccount( DataDirectoryService.GetMainDirectoryWithApplicationName("TradeLog")); } accountLastSaveTime = DateTime.UtcNow; } // Re-connect if connect is lost if (DateTime.UtcNow >= nextFxcmConnectedCheckTime) { nextFxcmConnectedCheckTime = DateTime.UtcNow.AddSeconds(checkFxcmConnectedIntervalSeconds); if (_fxcm.Status == ConnectStatus.Disconnected) { Log.Warn("FXCM has disconnected - reconnecting"); try { priceMonitor?.Dispose(); } catch (Exception ex) { Log.Error("Unable to dispose price monitor", ex); } priceMonitor = null; _fxcm.Connect(); if (_fxcm.Status == ConnectStatus.Connected) { Log.Warn($"FXCM has reconnected"); priceMonitor = new MonitorLivePrices(_fxcm, p => ProcessNewPrice(markets, timeframes, p, candlesLookup)); } else { Log.Warn($"FXCM hasn't re-connected - new status is: {_fxcm.Status}"); } } } foreach (var strategy in strategyLookup.Values) { var newTimeframeCandles = new List <Timeframe>(); // Check if there is any new complete candles foreach (var t in strategy.Timeframes) { lock (candlesLookup[strategy.Market.Name][t]) { if (strategy.Candles[t].Count != candlesLookup[strategy.Market.Name][t].Count(c => c.IsComplete == 1)) { newTimeframeCandles.Add(t); strategy.Candles[t].Clear(); strategy.Candles[t].AddRange(candlesLookup[strategy.Market.Name][t] .Where(c => c.IsComplete == 1).ToList()); } } } if (newTimeframeCandles.Any()) // TODO reduce times this is called and include save { // Update broker account lock (_brokerAccount) { Log.Debug("Updating and saving broker account"); _brokerAccount.UpdateBrokerAccount(_fxcm, _candlesService, _marketDetailsService, _tradeDetailsAutoCalculatorService, UpdateOption.ForceUpdate); } var s = strategy; Task.Run(() => { if (Monitor.TryEnter(_marketLock[s.Market.Name])) { try { Log.Info($"Found new candles for market: {s.Market.Name}"); // Update indicators and do trades maintenance s.UpdateIndicators(newTimeframeCandles); s.NewTrades.Clear(); s.Trades.MoveTrades(); var beforeStopLossLookup = s.Trades.OpenTrades.ToDictionary(x => x.Trade.Id, x => x.Trade.StopPrice); // Process strategy s.ProcessCandles(newTimeframeCandles); // Create any new trades CreateNewFXCMTradesAndUpdateAccount(s); if (trades.OpenTrades.Count() > 5) { Log.Error("Too many trades"); } // Update any stops UpdateFXCMOpenTradesStops(s, beforeStopLossLookup); } finally { Monitor.Exit(_marketLock[s.Market.Name]); } } }); } } Thread.Sleep(100); } } finally { priceMonitor.Dispose(); } }