Example #1
0
        private Execution ExecuteArbitrageParallel(Arbitrage arbitrage)
        {
            Execution execution = new Execution(arbitrage);

            Parallel.ForEach(execution.GetSequence(), sequence =>
            {
                Int32 offset        = sequence.Item1;
                TriangulationStep x = sequence.Item2;
                TriangulationStep y = sequence.Item3;

                if (!Config.TradingEnabled)
                {
                    m_ExchangeEngine.TestOrder(x.Position, x.Symbol, arbitrage.GetQuantity(offset));
                    return;
                }

                OrderResult result = m_ExchangeEngine.PlaceOrder(x.Position, x.Symbol, arbitrage.GetQuantity(offset));

                if (x.Position == Position.Buy)
                {
                    x.Out = result.OtherQuantity;
                    y.In  = result.ExecutedQuantity;
                }
                else
                {
                    x.Out = result.ExecutedQuantity;
                    y.In  = result.OtherQuantity;
                }

                execution.Fees += result.Fees;
            });

            return(execution);
        }
Example #2
0
        private static Arbitrage DetectArbitrage(Trade trade, Decimal quantity, SortedOrderBook[] orderBooks)
        {
            try
            {
                DateTime  referenceTime = orderBooks.Min(x => x.UpdateTime);
                Arbitrage arbitrage     = new Arbitrage(referenceTime, trade);

                foreach ((Int32 offset, TriangulationStep x, TriangulationStep y) in arbitrage.GetSequence())
                {
                    if (x.Position == Position.Buy)
                    {
                        SortedOrderBook orderBook      = orderBooks[offset];
                        Decimal         dustedQuantity = OrderBookConversion(false, quantity, x.ReferenceAsset, y.ReferenceAsset, orderBook);

                        y.In  = CalculateDustless(dustedQuantity, x.DustDecimals);
                        x.Out = OrderBookConversion(true, y.In, y.ReferenceAsset, x.ReferenceAsset, orderBook);
                    }
                    else
                    {
                        x.Out = CalculateDustless(quantity, x.DustDecimals);
                        y.In  = OrderBookConversion(false, x.Out, x.ReferenceAsset, y.ReferenceAsset, orderBooks[offset]);
                    }

                    quantity = y.In;
                }

                return(arbitrage);
            }
            catch
            {
                return(null);
            }
        }
Example #3
0
        private Execution ExecuteArbitrageSequential(Arbitrage arbitrage)
        {
            Decimal?  recalculatedQuantity = null;
            Execution execution            = new Execution(arbitrage);

            foreach ((Int32 offset, TriangulationStep x, TriangulationStep y) in execution.GetSequence())
            {
                Decimal quantity = recalculatedQuantity ?? arbitrage.GetQuantity(offset);

                if (!Config.TradingEnabled)
                {
                    m_ExchangeEngine.TestOrder(x.Position, x.Symbol, quantity);
                    continue;
                }

                OrderResult result = m_ExchangeEngine.PlaceOrder(x.Position, x.Symbol, quantity);

                if (x.Position == Position.Buy)
                {
                    x.Out = result.OtherQuantity;
                    y.In  = result.ExecutedQuantity;

                    SortedOrderBook orderBook = m_ExchangeEngine.GetOrderBook(y.Symbol);
                    recalculatedQuantity = CalculateDustless(OrderBookConversion(false, y.In, y.QuoteAsset, y.BaseAsset, orderBook), y.DustDecimals);
                }
                else
                {
                    x.Out = result.ExecutedQuantity;
                    y.In  = result.OtherQuantity;

                    recalculatedQuantity = CalculateDustless(y.In, y.DustDecimals);
                }

                execution.Fees += result.Fees;
            }

            return(execution);
        }
Example #4
0
        private void DetectArbitrages()
        {
            if (m_Trading)
            {
                m_MessagePump.Signal(Utilities.FormatMessage(Resources.CycleSkipped, Config.TradingCyclesDelay));
                return;
            }

            m_Trading = true;

            DateTime            start  = DateTime.Now;
            ICollection <Trade> trades = m_ExchangeEngine.GetTrades();
            IDictionary <String, SortedOrderBook> orderBooks = m_ExchangeEngine.GetOrderBooks();

            Parallel.ForEach(trades, trade =>
            {
                SortedOrderBook orderBook1 = orderBooks[trade.Leg1.Symbol];

                if (orderBook1.Invalid)
                {
                    return;
                }

                SortedOrderBook orderBook2 = orderBooks[trade.Leg2.Symbol];

                if (orderBook2.Invalid)
                {
                    return;
                }

                SortedOrderBook orderBook3 = orderBooks[trade.Leg3.Symbol];

                if (orderBook3.Invalid)
                {
                    return;
                }

                Arbitrage bestArbitrage           = null;
                SortedOrderBook[] orderBooksArray = { orderBook1, orderBook2, orderBook3 };

                for (Decimal quantity = Config.InvestmentMinimum; quantity <= Config.InvestmentMaximum; quantity += Config.InvestmentStep)
                {
                    Arbitrage arbitrage = DetectArbitrage(trade, quantity, orderBooksArray);

                    if ((arbitrage == null) || (arbitrage.Profit <= 0M))
                    {
                        continue;
                    }

                    if ((bestArbitrage == null) || (arbitrage.Profit > bestArbitrage.Profit))
                    {
                        bestArbitrage = arbitrage;
                    }
                }

                if (bestArbitrage != null)
                {
                    m_Arbitrages.Add(bestArbitrage);
                }
            });

            Int32 duration = (DateTime.Now - start).Milliseconds;

            if (m_CycleDurations.Count == 300)
            {
                m_CycleDurations.RemoveAt(0);
            }

            m_CycleDurations.Add(duration);

            m_MessagePump.Signal(Utilities.FormatMessage(Resources.CycleCompleted, duration, $"{(Int32)Math.Round(m_CycleDurations.Average(), 0)}"));

            m_Trading = false;
        }
Example #5
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);
        }