Beispiel #1
0
        public TradingEngine(MessagePump messagePump, ExchangeEngine exchangeEngine)
        {
            m_MessagePump    = messagePump ?? throw new ArgumentNullException(nameof(messagePump));
            m_ExchangeEngine = exchangeEngine ?? throw new ArgumentNullException(nameof(exchangeEngine));

            if (!m_ExchangeEngine.Initialized)
            {
                throw new Exception(Resources.EngineNotInitialized);
            }

            m_Arbitrages       = new BlockingCollection <Arbitrage>(new ConcurrentQueue <Arbitrage>());
            m_Executions       = new Dictionary <DateTime, Execution>();
            m_ExecutionSymbols = new HashSet <String>();
            m_CycleDurations   = new List <Int32>();

            String session      = Utilities.FormatMessage(Resources.TradingSession, $"{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
            String sessionFrame = new String('*', session.Length);

            m_MessagePump.Signal(sessionFrame);
            m_MessagePump.Signal(session);
            m_MessagePump.Signal(sessionFrame);

            m_Consumer = Task.Factory.StartNew(() =>
            {
                foreach (Arbitrage arbitrage in m_Arbitrages.GetConsumingEnumerable())
                {
                    Task.Run(() => ExecuteArbitrage(arbitrage));
                }
            },
                                               CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);

            m_Producer = Task.Factory.StartNew(() =>
            {
                Thread.Sleep(Config.TradingCyclesDelay * 10);

                while (!m_Arbitrages.IsCompleted)
                {
                    Task.Run(() => DetectArbitrages());
                    Thread.Sleep(Config.TradingCyclesDelay);
                }
            },
                                               CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
        }
Beispiel #2
0
        private void ExecuteArbitrage(Arbitrage arbitrage)
        {
            MessageCollection message = new MessageCollection(true, Utilities.FormatMessage(Resources.ArbitrageFound, arbitrage.Identifier, $"{arbitrage.Profit:F4}"));

            if (Config.TradingEnabled && (Config.TradingExecutionsCap > 0) && (m_Executions.Count >= Config.TradingExecutionsCap))
            {
                message.AppendMessage(Utilities.FormatMessage(Resources.ArbitrageDiscardedCap, Config.TradingExecutionsCap));
                m_MessagePump.Signal(message);
                return;
            }

            if (arbitrage.Profit < Config.TradingThresholdProfit)
            {
                message.AppendMessage(Utilities.FormatMessage(Resources.ArbitrageDiscardedProfit, $"{Config.TradingThresholdProfit:F4}"));
                return;
            }

            if (m_ExecutionSymbols.Any(arbitrage.GetReferenceAssets().Contains))
            {
                message.AppendMessage(Resources.ArbitrageDiscardedAssets);
                m_MessagePump.Signal(message);
                return;
            }

            if (m_Executions.Count(x => x.Key >= DateTime.Now.AddSeconds(-1d)) > 1)
            {
                message.AppendMessage(Resources.ArbitrageDiscardedCooldown);
                m_MessagePump.Signal(message);
                return;
            }

            Int32 age = (DateTime.Now - arbitrage.ReferenceTime).Milliseconds;

            if (age > Config.TradingThresholdAge)
            {
                message.AppendMessage(Utilities.FormatMessage(Resources.ArbitrageDiscardedAge, age, Config.TradingThresholdAge));
                m_MessagePump.Signal(message);
                return;
            }

            foreach (String referenceAsset in arbitrage.GetReferenceAssets())
            {
                m_ExecutionSymbols.Add(referenceAsset);
            }

            try
            {
                Execution execution;

                if (Config.TradingStrategy == Strategy.Parallel)
                {
                    execution = ExecuteArbitrageParallel(arbitrage);
                }
                else
                {
                    execution = ExecuteArbitrageSequential(arbitrage);
                }

                m_Executions[DateTime.Now] = execution;

                message.AppendMessage(Utilities.FormatMessage(Resources.ArbitrageSucceded, Config.TradingStrategy.ToString().ToUpperInvariant()));

                foreach (var zip in arbitrage.GetSequence().Zip(execution.GetSequence(), (e, o) => new { Expected = e, Observed = o }))
                {
                    Int32 offset = zip.Expected.Item1;

                    TriangulationStep eX = zip.Expected.Item2;
                    TriangulationStep eY = zip.Expected.Item3;

                    TriangulationStep oX = zip.Observed.Item2;
                    TriangulationStep oY = zip.Observed.Item3;

                    message.AppendMessage(Utilities.FormatMessage(Resources.ArbitrageStep, offset));
                    message.AppendMessage(Utilities.FormatMessage(Resources.ArbitrageExpectedConversion, $"{eX.Out:F8}", eX.ReferenceAsset, $"{eY.Out:F8}", eY.ReferenceAsset));
                    message.AppendMessage(Utilities.FormatMessage(Resources.ArbitrageObservedConversion, $"{oX.Out:F8}", oX.ReferenceAsset, $"{oY.Out:F8}", oY.ReferenceAsset));
                }

                message.AppendMessage(Resources.ArbitrageDeltas);

                foreach (TriangulationStep step in execution.GetSteps())
                {
                    Decimal eDelta   = step.Delta;
                    Decimal ePercent = (eDelta / step.Out) * 100M;

                    message.AppendMessage(Utilities.FormatMessage(Resources.ArbitrageDelta, step.ReferenceAsset, (eDelta < 0M) ? String.Empty : " ", $"{eDelta:F8}", $"{ePercent:F4}"));
                }

                message.AppendMessage(Resources.ArbitrageOthers);
                message.AppendMessage(Utilities.FormatMessage(Resources.ArbitrageCommission, $"{(-1M * execution.Fees):F8}"));
            }
            catch (Exception e)
            {
                message.AppendMessage(Utilities.FormatMessage(Resources.ArbitrageFailed, Config.TradingStrategy.ToString().ToUpperInvariant(), Utilities.GetExceptionMessage(e)));
            }

            foreach (String referenceAsset in arbitrage.GetReferenceAssets())
            {
                m_ExecutionSymbols.Remove(referenceAsset);
            }

            m_MessagePump.Signal(message);
        }