コード例 #1
0
        public override async Task <ExecutionReport> AddOrderAndWaitExecution(TradingSignal signal, TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            var newOrderSingle = new NewOrderSingle
            {
                HandlInst    = new HandlInst(HandlInst.AUTOMATED_EXECUTION_ORDER_PRIVATE),
                Symbol       = _modelConverter.ConvertLykkeSymbol(signal.Instrument.Name),
                Side         = _modelConverter.ConvertSide(signal.TradeType),
                OrderQty     = new OrderQty(signal.Volume),
                OrdType      = _modelConverter.ConverOrderType(signal.OrderType),
                TimeInForce  = new TimeInForce(TimeInForce.IMMEDIATE_OR_CANCEL),
                TransactTime = new TransactTime(DateTime.UtcNow),
                Price        = new Price(signal.Price ?? 0m)
            };

            var cts    = new CancellationTokenSource(timeout);
            var report = await _connector.AddOrderAsync(newOrderSingle, cts.Token);


            var trade = _modelConverter.ConvertExecutionReport(report);

            try
            {
                var handlerTrade = _modelConverter.ConvertExecutionReport(report);
                handlerTrade.ExecType = ExecType.Trade;
                await _executionHandler.Handle(handlerTrade);
            }
            catch (Exception ex)
            {
                await _log.WriteErrorAsync(nameof(AddOrderAndWaitExecution), "Posting order to Jfd", ex);
            }
            return(trade);
        }
コード例 #2
0
        /// <summary>
        /// Adds the signal.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name">The name.</param>
        /// <param name="action">The action.</param>
        /// <param name="trigger">The trigger.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">Universe trigger is empty for adding a trading event</exception>
        public TradingSignal AddSignal <T>(string name, Func <Security, bool> action, Dictionary <Security, T> trigger)
            where T : IndicatorBase <IndicatorDataPoint>
        {
            if (trigger.Count == 0)
            {
                throw new ArgumentNullException("Universe trigger is empty for adding a trading event");
            }

            //Get first item
            var foundtrigger = trigger.Values.First();

            //Create trading event
            TradingSignal nevent = new TradingSignal(Universe, name, action);

            foundtrigger.Updated += (sender, updated) =>
            {
                if (IsRunning)
                {
                    nevent.Execute();
                }
            };
            nevent.SignalFired  += OnSignal;
            Signals[nevent.Name] = nevent;
            return(nevent);
        }
コード例 #3
0
        /// <summary>
        /// Adds the signal.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="action">The action.</param>
        /// <returns></returns>
        public TradingSignal AddSignal(string name, Func <Security, bool> action)
        {
            TradingSignal nevent = new TradingSignal(Universe, name, action);

            Signals[nevent.Name] = nevent;
            return(nevent);
        }
コード例 #4
0
        public override async Task <ExecutionReport> CancelOrderAndWaitExecution(
            TradingSignal signal, TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            if (!Guid.TryParse(signal.OrderId, out var id))
            {
                throw new ApiException("GDAX order id can be only Guid");
            }

            var cts = CreateCancellationTokenSource(timeout);

            try
            {
                var response = await _restApi.CancelOrder(id, cts.Token,
                                                          (sender, httpRequest) => OnSentHttpRequest(httpRequest, translatedSignal),
                                                          (sender, httpResponse) => OnReceivedHttpRequest(httpResponse, translatedSignal));

                if (!response)
                {
                    return(null);
                }

                return(null);  // TODO: Here we should just return boolean result
            }
            catch (StatusCodeException ex)
            {
                throw new ApiException(ex.Message);
            }
        }
コード例 #5
0
        public void SetSignal(TradingSignal signal)
        {
            TextView id = FindViewById <TextView>(Resource.Id.tv_ID_Value);

            id.Text = signal.Id.ToString();
            TextView actualTime = FindViewById <TextView>(Resource.Id.tv_Act_Time_Value);

            actualTime.Text = signal.ActualTime;
            TextView comment = FindViewById <TextView>(Resource.Id.tv_comment_Value);

            comment.Text = signal.Comment;
            TextView pair = FindViewById <TextView>(Resource.Id.tv_pair_Value);

            pair.Text = signal.Pair;
            TextView cmd = FindViewById <TextView>(Resource.Id.tv_cmd_Value);

            cmd.Text = signal.Cmd.ToString();
            TextView system = FindViewById <TextView>(Resource.Id.tv_trading_System_Value);

            system.Text = signal.TradingSystem.ToString();
            TextView period = FindViewById <TextView>(Resource.Id.tv_period_Value);

            period.Text = signal.Period;
            TextView price = FindViewById <TextView>(Resource.Id.tv_price_Value);

            price.Text = Math.Round(signal.Price, 5).ToString();
            TextView sl = FindViewById <TextView>(Resource.Id.tv_sl_Value);

            sl.Text = Math.Round(signal.Sl, 5).ToString();
            TextView tp = FindViewById <TextView>(Resource.Id.tv_tp_Value);

            tp.Text = Math.Round(signal.Tp, 5).ToString();
        }
コード例 #6
0
        public override async Task <ExecutionReport> AddOrderAndWaitExecution(TradingSignal signal, TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            var cts      = new CancellationTokenSource(timeout);
            var request  = _converter.CreateNewOrderSingle(signal);
            var response = await _tradeSessionConnector.AddOrderAsync(request, cts.Token);

            return(_converter.ConvertExecutionReport(response));
        }
コード例 #7
0
 public AddStandardOrderRequest(TradingSignal tradingSignal, IReadOnlyCollection <CurrencySymbol> currencySymbols)
 {
     Pair      = currencySymbols.Single(x => x.LykkeSymbol == tradingSignal.Instrument.Name).ExchangeSymbol;
     Type      = tradingSignal.TradeType;
     OrderType = tradingSignal.OrderType;
     Price     = tradingSignal.Price ?? 0;
     Volume    = tradingSignal.Volume;
 }
コード例 #8
0
 /// <summary>
 /// Called when a trading signal is activated.
 /// </summary>
 /// <param name="signal">The signal.</param>
 /// <param name="securities">The securities.</param>
 public override void OnSignal(TradingSignal signal, Security[] securities)
 {
     //Check signals
     if (signal == CrossedOver)
     {
         EnterLong(securities);
     }
     else if (signal == CrossedBelow)
     {
         EnterShort(securities);
     }
 }
コード例 #9
0
        public void TradingSignal_IsTimeInThreshold()
        {
            var signal = new TradingSignal(null, "", OrderCommand.Create, TradeType.Buy, 100m, 100m, DateTime.UtcNow.AddMinutes(-5));

            Assert.True(signal.IsTimeInThreshold(TimeSpan.FromMinutes(6)));
            Assert.False(signal.IsTimeInThreshold(TimeSpan.FromMinutes(4)));

            var signalInFuture = new TradingSignal(null, "", OrderCommand.Create, TradeType.Buy, 100m, 100m, DateTime.UtcNow.AddMinutes(5));

            Assert.True(signalInFuture.IsTimeInThreshold(TimeSpan.FromMinutes(6)));
            Assert.False(signalInFuture.IsTimeInThreshold(TimeSpan.FromMinutes(4)));
        }
コード例 #10
0
        public override async Task <ExecutionReport> AddOrderAndWaitExecution(TradingSignal signal,
                                                                              TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            var cts = new CancellationTokenSource(timeout);

            var orderInfo = await privateData.AddOrder(signal, translatedSignal, cts.Token);

            string txId = orderInfo.TxId.FirstOrDefault();

            translatedSignal.ExternalId = txId;

            return(new ExecutionReport(signal.Instrument, DateTime.UtcNow, signal.Price ?? 0, signal.Volume, signal.TradeType, signal.OrderId, OrderExecutionStatus.New));
        }
コード例 #11
0
        public override async Task <ExecutionReport> CancelOrderAndWaitExecution(TradingSignal signal, TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            var ct       = new CancellationTokenSource(timeout);
            var id       = signal.OrderId;
            var response = await _exchangeApi.OrdercancelAsync(cancellationToken : ct.Token, orderID : id);

            if (response is Error error)
            {
                throw new ApiException(error.ErrorProperty.Message);
            }
            var res = EnsureCorrectResponse(id, response);

            return(BitMexModelConverter.OrderToTrade(res[0]));
        }
コード例 #12
0
        /// <summary>
        /// Adds the signal.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="action">The action.</param>
        /// <param name="interval">The interval.</param>
        /// <returns></returns>
        public TradingSignal AddSignal(string name, Func <Security, bool> action, TimeSpan interval)
        {
            TradingSignal nevent = new TradingSignal(Universe, name, action, true);

            ScheduledActionsKeeper.Event(QuantFund.FundId, Date.EveryDay(), Time.Every(interval), () =>
            {
                if (IsRunning)
                {
                    nevent.Execute();
                }
            });
            Signals[nevent.Name] = nevent;
            return(nevent);
        }
コード例 #13
0
        public override async Task <ExecutionReport> CancelOrderAndWaitExecution(TradingSignal signal,
                                                                                 TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            var cts = new CancellationTokenSource(timeout);

            string result = await apiClient.MakePostRequestAsync <string>(
                $"{Config.EndpointUrl}/api/Orders/{signal.OrderId}/Cancel",
                CreateHttpContent(new object()),
                translatedSignal.RequestSent, translatedSignal.ResponseReceived,
                cts.Token);

            return(new ExecutionReport(signal.Instrument, DateTime.UtcNow, signal.Price ?? 0, signal.Volume, signal.TradeType,
                                       signal.OrderId, OrderExecutionStatus.Cancelled));
        }
コード例 #14
0
        /// <summary>
        /// Adds the signal.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="action">The action.</param>
        /// <param name="trigger">The trigger.</param>
        /// <returns></returns>
        public TradingSignal AddSignal(string name, Func <Security, bool> action, DataAggregator trigger)
        {
            TradingSignal nevent = new TradingSignal(Universe, name, action);

            trigger.DataAggregated += (sender, aggregate) =>
            {
                if (IsRunning)
                {
                    nevent.Execute();
                }
            };
            nevent.SignalFired  += OnSignal;
            Signals[nevent.Name] = nevent;
            return(nevent);
        }
コード例 #15
0
        public async Task <ExecutionReport> CancelOrder(string id, [FromQuery, Required] string exchangeName)
        {
            try
            {
                if (string.IsNullOrEmpty(exchangeName))
                {
                    throw new StatusCodeException(HttpStatusCode.InternalServerError, "Exchange has to be specified");
                }

                var instrument    = new Instrument(exchangeName, string.Empty);
                var tradingSignal = new TradingSignal(instrument, id, OrderCommand.Cancel, TradeType.Unknown, 0, 0, DateTime.UtcNow, OrderType.Unknown);

                var translatedSignal = new TranslatedSignalTableEntity(SignalSource.RestApi, tradingSignal)
                {
                    ClientIP = HttpContext.Connection.RemoteIpAddress.ToString()
                };

                try
                {
                    var result = await Application.GetExchange(exchangeName)
                                 .CancelOrderAndWaitExecution(tradingSignal, translatedSignal, _timeout);

                    if (result.ExecutionStatus == OrderExecutionStatus.Rejected)
                    {
                        throw new StatusCodeException(HttpStatusCode.BadRequest, $"Exchange return status: {result.ExecutionStatus}", null);
                    }

                    return(result);
                }
                catch (Exception e)
                {
                    translatedSignal.Failure(e);
                    throw;
                }
                finally
                {
                    await _translatedSignalsRepository.SaveAsync(translatedSignal);
                }
            }
            catch (StatusCodeException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new StatusCodeException(HttpStatusCode.InternalServerError, e.Message, e);
            }
        }
コード例 #16
0
        public NewOrderSingle CreateNewOrderSingle(TradingSignal tradingSignal)
        {
            var newOrderSingle = new NewOrderSingle
            {
                Symbol       = new Symbol(LykkeSymbolToExchangeSymbol(tradingSignal.Instrument.Name)),
                Currency     = new Currency(tradingSignal.Instrument.Base),
                Side         = ConvertSide(tradingSignal.TradeType),
                OrderQty     = new OrderQty(tradingSignal.Volume),
                OrdType      = ConvertOrderType(tradingSignal.OrderType),
                TimeInForce  = new TimeInForce(TimeInForce.IMMEDIATE_OR_CANCEL),
                TransactTime = new TransactTime(DateTime.UtcNow),
                Price        = new Price(tradingSignal.Price ?? 0m)
            };

            return(newOrderSingle);
        }
コード例 #17
0
        public override async Task <ExecutionReport> CancelOrderAndWaitExecution(TradingSignal signal, TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            var result = await privateData.CancelOrder(signal.OrderId, translatedSignal);

            var executedTrade = new ExecutionReport(signal.Instrument,
                                                    DateTime.UtcNow,
                                                    signal.Price ?? 0,
                                                    signal.Volume,
                                                    signal.TradeType,
                                                    signal.OrderId,
                                                    result.Pending ? OrderExecutionStatus.Pending : OrderExecutionStatus.Cancelled);

            translatedSignal.SetExecutionResult(executedTrade);

            return(executedTrade);
        }
コード例 #18
0
        /// <summary>
        /// Adds the signal.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name">The name.</param>
        /// <param name="action">The action.</param>
        /// <param name="trigger">The trigger.</param>
        /// <returns></returns>
        public TradingSignal AddSignal <T>(string name, Func <Security, bool> action, T trigger)
            where T : IndicatorBase <IndicatorDataPoint>
        {
            TradingSignal nevent = new TradingSignal(Universe, name, action);

            trigger.Updated += (sender, updated) =>
            {
                if (IsRunning)
                {
                    nevent.Execute();
                }
            };
            nevent.SignalFired  += OnSignal;
            Signals[nevent.Name] = nevent;
            return(nevent);
        }
コード例 #19
0
 public void SetSignal(TradingSignal signal)
 {
     if (signal == null)
     {
         return;
     }
     lb_ID.Text            = signal.Id.ToString();
     lb_ActualTime.Text    = signal.ActualTime;
     lb_Comment.Text       = signal.Comment;
     lb_Pair.Text          = signal.Pair;
     lb_CMD.Text           = signal.Cmd.ToString();
     lb_Price.Text         = Math.Round(signal.Price, 5).ToString();
     lb_SL.Text            = Math.Round(signal.Sl, 5).ToString();
     lb_TP.Text            = Math.Round(signal.Tp, 5).ToString();
     lb_TradingSystem.Text = signal.TradingSystem.ToString();
     lb_Period.Text        = signal.Period;
 }
コード例 #20
0
        public override Task <ExecutionReport> AddOrderAndWaitExecution(TradingSignal signal, TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            translatedSignal.RequestSentMessage("stub exchange don't send actual request");
//
//	        SimulateWork();
//	        SimulateException();
//
            translatedSignal.ResponseReceived("stub exchange don't recevie actual response");
            lock (syncRoot)
            {
                var s = new TradingSignal(signal.Instrument, Guid.NewGuid().ToString(), signal.Command, signal.TradeType, signal.Price, signal.Volume, signal.Time, signal.OrderType, signal.TimeInForce);
                ActualSignals[signal.Instrument.Name].AddLast(s);
                translatedSignal.ExternalId = s.OrderId;

                return(Task.FromResult(new ExecutionReport(s.Instrument, DateTime.UtcNow, s.Price ?? 0, s.Volume, s.TradeType, s.OrderId, OrderExecutionStatus.New)));
            }
        }
コード例 #21
0
        public TranslatedSignalTableEntity(SignalSource signalSource, TradingSignal signal)
        {
            ReceiveDateTime = DateTime.UtcNow;
            Status          = TranslationStatus.Success;

            SignalSource = signalSource;
            Exchange     = signal.Instrument.Exchange;
            Instrument   = signal.Instrument.Name;

            SignalDateTime = signal.Time;
            OrderCommand   = signal.Command;
            OrderId        = signal.OrderId;
            Price          = signal.Price;
            Volume         = signal.Volume;
            OrderType      = signal.OrderType;
            TradeType      = signal.TradeType;
            TimeInForce    = signal.TimeInForce;
        }
コード例 #22
0
        public void SerializeAndDeserializeTradingSignal()
        {
            var converter = new GenericRabbitModelConverter <TradingSignal>();
            var signal    = new TradingSignal(new Instrument("Exchange", "EURUSD"), "", OrderCommand.Create, TradeType.Buy, 100.2m, 10.1m, DateTime.UtcNow, OrderType.Limit);

            var serialized = converter.Serialize(signal);

            Assert.NotNull(serialized);

            var deserialized = converter.Deserialize(serialized);

            Assert.Equal(signal.TradeType, deserialized.TradeType);
            Assert.Equal(signal.Volume, deserialized.Volume);
            Assert.Equal(signal.OrderType, deserialized.OrderType);
            Assert.Equal(signal.Time, deserialized.Time);
            Assert.Equal(signal.OrderId, deserialized.OrderId);
            Assert.Equal(signal.Command, deserialized.Command);
        }
コード例 #23
0
        public override async Task <ExecutionReport> CancelOrderAndWaitExecution(TradingSignal signal, TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            var cts = new CancellationTokenSource(timeout);

            if (!long.TryParse(signal.OrderId, out var id))
            {
                throw new ApiException("Bitfinex order id can be only integer");
            }
            var response = await _exchangeApi.CancelOrder(id, cts.Token);

            if (response is Error error)
            {
                throw new ApiException(error.Message);
            }
            var trade = OrderToTrade((Order)response);

            return(trade);
        }
コード例 #24
0
        public override async Task <ExecutionReport> AddOrderAndWaitExecution(TradingSignal signal, TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            var symbol    = "XBTUSD"; //HACK Hard code!
            var volume    = BitMexModelConverter.ConvertVolume(signal.Volume);
            var orderType = BitMexModelConverter.ConvertOrderType(signal.OrderType);
            var side      = BitMexModelConverter.ConvertTradeType(signal.TradeType);
            var price     = (double?)signal.Price;
            var ct        = new CancellationTokenSource(timeout);

            var response = await _exchangeApi.OrdernewAsync(symbol, orderQty : volume, price : price, clOrdID : signal.OrderId, ordType : orderType, side : side, cancellationToken : ct.Token);

            if (response is Error error)
            {
                throw new ApiException(error.ErrorProperty.Message);
            }

            var order = (Order)response;

            return(BitMexModelConverter.OrderToTrade(order));
        }
コード例 #25
0
        public override async Task <ExecutionReport> AddOrderAndWaitExecution(TradingSignal signal, TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            var symbol    = _modelConverter.LykkeSymbolToExchangeSymbol(signal.Instrument.Name);
            var volume    = signal.Volume;
            var orderType = _modelConverter.ConvertOrderType(signal.OrderType);
            var side      = _modelConverter.ConvertTradeType(signal.TradeType);
            var price     = signal.Price == 0 ? 1 : signal.Price ?? 1;
            var cts       = new CancellationTokenSource(timeout);

            var response = await _exchangeApi.AddOrder(symbol, volume, price, side, orderType, cts.Token);

            if (response is Error error)
            {
                throw new ApiException(error.Message);
            }

            var trade = OrderToTrade((Order)response);

            return(trade);
        }
コード例 #26
0
        public Task Handle(TradingSignal message)
        {
            if (message == null || message.Instrument == null || string.IsNullOrEmpty(message.Instrument.Name))
            {
                return(logger.WriteWarningAsync(
                           nameof(TradingSignalsHandler),
                           nameof(Handle),
                           message?.ToString(),
                           "Received an unconsistent signal"));
            }

            if (!exchanges.ContainsKey(message.Instrument.Exchange))
            {
                return(logger.WriteWarningAsync(
                           nameof(TradingSignalsHandler),
                           nameof(Handle),
                           message.ToString(),
                           $"Received a trading signal for unconnected exchange {message.Instrument.Exchange}"));
            }

            return(HandleTradingSignals(exchanges[message.Instrument.Exchange], message));
        }
コード例 #27
0
        public override Task <ExecutionReport> CancelOrderAndWaitExecution(TradingSignal signal, TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            translatedSignal.RequestSentMessage("stub exchange don't send actual request");
//	        SimulateWork();
//	        SimulateException();
            translatedSignal.ResponseReceived("stub exchange don't recevie actual response");

            bool isCanceled = false;

            lock (syncRoot)
            {
                TradingSignal existing = ActualSignals[signal.Instrument.Name].FirstOrDefault(x => x.OrderId == signal.OrderId);
                if (existing != null)
                {
                    ActualSignals[signal.Instrument.Name].Remove(existing);
                    isCanceled = true;
                }
            }

            return(Task.FromResult(new ExecutionReport(signal.Instrument, DateTime.UtcNow, signal.Price ?? 0, signal.Volume, signal.TradeType, signal.OrderId,
                                                       isCanceled ? OrderExecutionStatus.Cancelled : OrderExecutionStatus.Unknown)));
        }
コード例 #28
0
        private async Task HandleCancellation(TradingSignal signal, TranslatedSignalTableEntity translatedSignal,
                                              Exchange exchange)
        {
            try
            {
                var executedTrade = await exchange.CancelOrderAndWaitExecution(signal, translatedSignal, apiTimeout);

                if (executedTrade.ExecutionStatus == OrderExecutionStatus.Cancelled)
                {
                    await _tradeHandler.Handle(executedTrade);
                }
                else
                {
                    var message = $"Executed trade status {executedTrade.ExecutionStatus} after calling 'exchange.CancelOrderAndWaitExecution'";
                    translatedSignal.Failure(message);
                    await logger.WriteWarningAsync(nameof(TradingSignalsHandler),
                                                   nameof(HandleCancellation),
                                                   signal.ToString(),
                                                   message);
                }
            }
            catch (ApiException e)
            {
                translatedSignal.Failure(e);
                await logger.WriteInfoAsync(nameof(TradingSignalsHandler), nameof(HandleCancellation),
                                            signal.ToString(),
                                            e.Message);
            }
            catch (Exception e)
            {
                translatedSignal.Failure(e);
                await logger.WriteErrorAsync(nameof(TradingSignalsHandler),
                                             nameof(HandleCancellation),
                                             signal.ToString(),
                                             e);
            }
        }
コード例 #29
0
        private async Task HandleTradingSignals(Exchange exchange, TradingSignal signal)
        {
            await logger.WriteInfoAsync(nameof(TradingSignalsHandler), nameof(HandleTradingSignals), signal.ToString(), "New trading signal to be handled.");

            var translatedSignal = new TranslatedSignalTableEntity(SignalSource.RabbitQueue, signal);

            try
            {
                switch (signal.Command)
                {
                case OrderCommand.Create:
                    await HandleCreation(signal, translatedSignal, exchange);

                    break;

                case OrderCommand.Cancel:
                    await HandleCancellation(signal, translatedSignal, exchange);

                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(signal));
                }
            }
            catch (Exception e)
            {
                translatedSignal.Failure(e);
            }
            finally
            {
                translatedSignalsRepository.Save(translatedSignal);

                await logger.WriteInfoAsync(nameof(TradingSignalsHandler), nameof(HandleTradingSignals),
                                            signal.ToString(), "Signal handled. Waiting for another one.");
            }
        }
コード例 #30
0
        public override async Task <ExecutionReport> AddOrderAndWaitExecution(TradingSignal signal,
                                                                              TranslatedSignalTableEntity translatedSignal, TimeSpan timeout)
        {
            var symbol    = _converters.LykkeSymbolToExchangeSymbol(signal.Instrument.Name);
            var orderType = _converters.OrderTypeToGdaxOrderType(signal.OrderType);
            var side      = _converters.TradeTypeToGdaxOrderSide(signal.TradeType);
            var volume    = signal.Volume;
            var price     = (!signal.Price.HasValue || signal.Price == 0) ? 1 : signal.Price.Value;
            var cts       = CreateCancellationTokenSource(timeout);

            try
            {
                var response = await _restApi.AddOrder(symbol, volume, price, side, orderType, cts.Token,
                                                       (sender, httpRequest) => OnSentHttpRequest(httpRequest, translatedSignal),
                                                       (sender, httpResponse) => OnReceivedHttpRequest(httpResponse, translatedSignal));

                var trade = _converters.OrderToTrade(response);
                return(trade);
            }
            catch (StatusCodeException ex)
            {
                throw new ApiException(ex.Message);
            }
        }