/// <summary> /// /// </summary> protected override string OnExecuteMarket(ISourceOrderExecution provider, OrderTypeEnum orderType, int volume, decimal? price, decimal? slippage, decimal? takeProfit, decimal? stopLoss, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { SystemMonitor.CheckError(provider.SupportsActiveOrderManagement, "Wrong position type for this provider."); executionInfo = PositionExecutionInfo.Empty; IQuoteProvider quoteProvider = _manager.ObtainQuoteProvider(_dataDelivery.SourceId, Symbol); if (quoteProvider == null) { operationResultMessage = "Failed to establish quote provider for [" + _dataDelivery.SourceId.Name + ", " + Symbol.Name + "]."; SystemMonitor.Error(operationResultMessage); return string.Empty; } price = ProcessPrice(quoteProvider, orderType, price); // New order shall be created. ActiveOrder order = new ActiveOrder(_manager, provider, quoteProvider, _dataDelivery.SourceId, Symbol, true); OrderInfo? infoReference; // Using the extended operationTimeOut to 40 seconds. bool result = provider.SynchronousExecute(provider.DefaultAccount.Info, order, _info.Symbol, orderType, volume, slippage, price, takeProfit, stopLoss, string.Empty, TimeSpan.FromSeconds(40), out infoReference, out operationResultMessage); if (result && infoReference.HasValue) { OrderInfo infoAssign = infoReference.Value; if (infoAssign.Type == OrderTypeEnum.UNKNOWN) { infoAssign.Type = orderType; } if (infoAssign.Volume == int.MinValue || infoAssign.Volume == int.MaxValue) {// Volume was not retrieved by integration. infoAssign.Volume = volume; } if (infoAssign.OpenPrice.HasValue) { executionInfo = new PositionExecutionInfo(infoReference.Value.Id, _dataDelivery.SourceId, provider.SourceId, Symbol, infoAssign.Type, infoAssign.OpenPrice.Value, volume, volume, infoAssign.OpenTime, PositionExecutionInfo.ExecutionResultEnum.Success); } else { SystemMonitor.Error("Received execution result, but price not assigned."); } order.AdoptInfo(infoAssign); provider.TradeEntities.AddOrder(order); return infoReference.Value.Id; } return string.Empty; }
/// <summary> /// This may contain a few operations on active orders, in order to match the rule "no opposing active orders" /// </summary> public virtual string ExecuteMarketBalanced(int volumeModification, decimal?desiredPrice, decimal?slippage, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { executionInfo = PositionExecutionInfo.Empty; ISourceOrderExecution provider = _orderProvider; if (provider == null || provider.DefaultAccount == null) { operationResultMessage = "Position not properly initialized."; return(string.Empty); } // Trace pre-execution info. string traceMessage = string.Format("Submit Volume Modification [{0}] Price [{1}] Slippage [{2}] TimeOut [{3}]", volumeModification.ToString(), GeneralHelper.ToString(desiredPrice), GeneralHelper.ToString(slippage), timeOut.ToString()); traceMessage += GenerateConditionsInfo(); TracerHelper.Trace(_tracer, traceMessage, TracerItem.PriorityEnum.High); if (OnExecuteMarketBalanced(provider, volumeModification, desiredPrice, slippage, timeOut, out executionInfo, out operationResultMessage)) { return(Guid.NewGuid().ToString()); } return(string.Empty); }
/// <summary> /// /// </summary> protected override string OnExecuteMarket(ISourceOrderExecution provider, OrderTypeEnum orderType, int volume, decimal?price, decimal?slippage, decimal?takeProfit, decimal?stopLoss, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { SystemMonitor.CheckError(provider.SupportsActiveOrderManagement == false, "Wrong position type for this provider."); executionInfo = PositionExecutionInfo.Empty; PassiveOrder order; lock (this) { order = new PassiveOrder(_manager, _dataDelivery.SourceId, provider.SourceId); } OrderInfo?infoReference; bool result = provider.SynchronousExecute(provider.DefaultAccount.Info, order, _info.Symbol, orderType, volume, slippage, price, takeProfit, stopLoss, string.Empty, out infoReference, out operationResultMessage); if (result && infoReference.HasValue) { OrderInfo infoAssign = infoReference.Value; if (infoAssign.Type == OrderTypeEnum.UNKNOWN) { infoAssign.Type = orderType; } if (infoAssign.Volume == int.MinValue || infoAssign.Volume == int.MaxValue) {// Volume was not retrieved by integration. infoAssign.Volume = volume; } if (infoAssign.OpenPrice.HasValue) { executionInfo = new PositionExecutionInfo(infoReference.Value.Id, _dataDelivery.SourceId, provider.SourceId, Symbol, infoAssign.Type, infoAssign.OpenPrice.Value, volume, volume, infoAssign.OpenTime, PositionExecutionInfo.ExecutionResultEnum.Success); } else { SystemMonitor.Error("Received execution result, but price not assigned."); } order.AdoptInfo(infoAssign); provider.TradeEntities.AddOrder(order); return(infoReference.Value.Id); } return(string.Empty); }
/// <summary> /// /// </summary> protected override string OnExecuteMarket(ISourceOrderExecution provider, OrderTypeEnum orderType, int volume, decimal? price, decimal? slippage, decimal? takeProfit, decimal? stopLoss, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { SystemMonitor.CheckError(provider.SupportsActiveOrderManagement == false, "Wrong position type for this provider."); executionInfo = PositionExecutionInfo.Empty; PassiveOrder order; lock (this) { order = new PassiveOrder(_manager, _dataDelivery.SourceId, provider.SourceId); } OrderInfo? infoReference; bool result = provider.SynchronousExecute(provider.DefaultAccount.Info, order, _info.Symbol, orderType, volume, slippage, price, takeProfit, stopLoss, string.Empty, out infoReference, out operationResultMessage); if (result && infoReference.HasValue) { OrderInfo infoAssign = infoReference.Value; if (infoAssign.Type == OrderTypeEnum.UNKNOWN) { infoAssign.Type = orderType; } if (infoAssign.Volume == int.MinValue || infoAssign.Volume == int.MaxValue) {// Volume was not retrieved by integration. infoAssign.Volume = volume; } if (infoAssign.OpenPrice.HasValue) { executionInfo = new PositionExecutionInfo(infoReference.Value.Id, _dataDelivery.SourceId, provider.SourceId, Symbol, infoAssign.Type, infoAssign.OpenPrice.Value, volume, volume, infoAssign.OpenTime, PositionExecutionInfo.ExecutionResultEnum.Success); } else { SystemMonitor.Error("Received execution result, but price not assigned."); } order.AdoptInfo(infoAssign); provider.TradeEntities.AddOrder(order); return infoReference.Value.Id; } return string.Empty; }
/// <summary> /// This may contain a few operations on active orders, in order to match the rule "no opposing active orders" /// </summary> public virtual string ExecuteMarketBalanced(int volumeModification, decimal?desiredPrice, decimal?slippage, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { executionInfo = PositionExecutionInfo.Empty; ISourceOrderExecution provider = _provider; if (provider == null || provider.DefaultAccount == null) { operationResultMessage = "Position not properly initialized."; return(string.Empty); } if (OnExecuteMarketBalanced(provider, volumeModification, desiredPrice, slippage, timeOut, out executionInfo, out operationResultMessage)) { return(Guid.NewGuid().ToString()); } return(string.Empty); }
/// <summary> /// /// </summary> public string ExecuteMarketBalancedClose(int?closeVolume, TimeSpan timeOut, out PositionExecutionInfo executionResult, out string operationResultMessage) { operationResultMessage = string.Empty; executionResult = PositionExecutionInfo.Empty; ISourceOrderExecution provider = _orderProvider; if (provider == null || provider.DefaultAccount == null) { operationResultMessage = "Position not initialized."; return(string.Empty); } if (Volume == 0) { operationResultMessage = "Position has no open volume (amount)."; return(string.Empty); } if (closeVolume.HasValue == false) { closeVolume = -(int)Volume; } else if (Volume > 0) {// Reverse of direction needed, since we make it directional. closeVolume = -closeVolume.Value; } if (Math.Abs(closeVolume.Value) > Math.Abs(Volume)) { operationResultMessage = "Volume (amount) to close too big."; return(string.Empty); } return(ExecuteMarketBalanced(closeVolume.Value, null, null, timeOut, out executionResult, out operationResultMessage)); }
///// <summary> ///// Will try to asynchronously reverse the given execution info position part. ///// Similar to the ExecuteMarketReverse baseMethod, only this is not synchronous. ///// </summary> //public virtual string SubmitReverse(PositionExecutionInfo orderInfo, decimal? slippage, bool manipulateExistingOrders, out string operationResultMessage) //{ // if (orderInfo.IsEmpty || orderInfo.Result != PositionExecutionInfo.ExecutionResultEnum.Success) // { // operationResultMessage = "Execution info not properly assigned for reversal."; // return string.Empty; // } // OrderTypeEnum orderType = OrderTypeEnum.UNKNOWN; // if (orderInfo.OrderType == OrderTypeEnum.BUY_MARKET) // { // orderType = OrderTypeEnum.SELL_MARKET; // } // else if (orderInfo.OrderType == OrderTypeEnum.SELL_MARKET) // { // orderType = OrderTypeEnum.BUY_MARKET; // } // else // { // operationResultMessage = "Only market position can be reversed."; // SystemMonitor.OperationError(operationResultMessage); // return string.Empty; // } // return Submit(orderType, (int)orderInfo.ExecutedVolume, // null, slippage, null, null, manipulateExistingOrders, out operationResultMessage); //} ///// <summary> ///// Will try to synchronously execute a reverse of the given execution info. ///// This is a suitable replacement for a specific "order close", i.e. allowing ///// you to reverse a specific previous execution on this position. ///// </summary> ///// <param name="orderInfo"></param> ///// <param name="allowExistingActiveOrdersManipulation">Is the operation allowed to close a matching existing order, or should we always open a new one. This is suitable for Active orders brokers, that dissallow hedged orders at the same time.</param> ///// <returns></returns> //public virtual string ExecuteMarketReverse(PositionExecutionInfo orderInfo, decimal? slippage, TimeSpan timeOut, bool manipulateExistingOrders, // out PositionExecutionInfo newExecutionInfo, out string operationResultMessage) //{ // newExecutionInfo = PositionExecutionInfo.Empty; // if (orderInfo.IsEmpty == false && orderInfo.Result == PositionExecutionInfo.ExecutionResultEnum.Success) // { // OrderTypeEnum orderType = OrderTypeEnum.UNKNOWN; // if (orderInfo.OrderType == OrderTypeEnum.BUY_MARKET) // { // orderType = OrderTypeEnum.SELL_MARKET; // } // else if (orderInfo.OrderType == OrderTypeEnum.SELL_MARKET) // { // orderType = OrderTypeEnum.BUY_MARKET; // } // else // { // operationResultMessage = "Only market position can be reversed."; // SystemMonitor.OperationError(operationResultMessage); // return string.Empty; // } // return ExecuteMarket(orderType, (int)orderInfo.ExecutedVolume, null, slippage, null, null, timeOut, out newExecutionInfo, out operationResultMessage); // } // else // { // operationResultMessage = "Can not reverse execution info with result [" + orderInfo.Result.ToString() + "], no action taken."; // SystemMonitor.OperationError(operationResultMessage); // return string.Empty; // } //} /// <summary> /// /// </summary> protected virtual bool OnExecuteMarketBalanced(ISourceOrderExecution provider, int volumeModification, decimal? desiredPrice, decimal? slippage, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { OrderTypeEnum orderType = OrderTypeEnum.BUY_MARKET; if (volumeModification < 0) { orderType = OrderTypeEnum.SELL_MARKET; } return string.IsNullOrEmpty(ExecuteMarket(orderType, Math.Abs(volumeModification), desiredPrice, slippage, null, null, timeOut, out executionInfo, out operationResultMessage)) == false; }
/// <summary> /// /// </summary> protected abstract string OnExecuteMarket(ISourceOrderExecution provider, OrderTypeEnum orderType, int volume, decimal?price, decimal?slippage, decimal?takeProfit, decimal?stopLoss, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage);
/// <summary> /// Places and tries to execute a market order synchronously. Since it might be a modification of an /// existing active order, no specific order Id is returned - instead a bool indicating operation result. /// </summary> /// <param name="manipulateExistingOrders">[where applicable] Is the operation allowed to close a matching existing order, or should we always open a new one. This is suitable for Active orders brokers, that dissallow hedged orders at the same time.</param> public string ExecuteMarket(OrderTypeEnum orderType, int volume, decimal?price, decimal?slippage, decimal?takeProfit, decimal?stopLoss, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { operationResultMessage = string.Empty; executionInfo = PositionExecutionInfo.Empty; ISourceOrderExecution provider = _orderProvider; if (provider == null || provider.DefaultAccount == null) { operationResultMessage = "Position not properly initialized."; return(string.Empty); } // Trace pre-execution info. string traceMessage = string.Format("Submit Type[{0}] Volume [{1}] Price [{2}] Slippage [{3}] TP [{4}] SL [{5}] TimeOut [{6}]", orderType.ToString(), volume.ToString(), GeneralHelper.ToString(price), GeneralHelper.ToString(slippage), GeneralHelper.ToString(takeProfit), GeneralHelper.ToString(stopLoss), timeOut.ToString()); traceMessage += GenerateConditionsInfo(); TracerHelper.Trace(_tracer, traceMessage, TracerItem.PriorityEnum.High); _isProcessing = true; string result = OnExecuteMarket(provider, orderType, volume, price, slippage, takeProfit, stopLoss, timeOut, out executionInfo, out operationResultMessage); SystemMonitor.CheckError(result == executionInfo.ExecutionId, operationResultMessage); _isProcessing = false; return(result); }
///// <summary> ///// Will try to asynchronously reverse the given execution info position part. ///// Similar to the ExecuteMarketReverse baseMethod, only this is not synchronous. ///// </summary> //public virtual string SubmitReverse(PositionExecutionInfo orderInfo, decimal? slippage, bool manipulateExistingOrders, out string operationResultMessage) //{ // if (orderInfo.IsEmpty || orderInfo.Result != PositionExecutionInfo.ExecutionResultEnum.Success) // { // operationResultMessage = "Execution info not properly assigned for reversal."; // return string.Empty; // } // OrderTypeEnum orderType = OrderTypeEnum.UNKNOWN; // if (orderInfo.OrderType == OrderTypeEnum.BUY_MARKET) // { // orderType = OrderTypeEnum.SELL_MARKET; // } // else if (orderInfo.OrderType == OrderTypeEnum.SELL_MARKET) // { // orderType = OrderTypeEnum.BUY_MARKET; // } // else // { // operationResultMessage = "Only market position can be reversed."; // SystemMonitor.OperationError(operationResultMessage); // return string.Empty; // } // return Submit(orderType, (int)orderInfo.ExecutedVolume, // null, slippage, null, null, manipulateExistingOrders, out operationResultMessage); //} ///// <summary> ///// Will try to synchronously execute a reverse of the given execution info. ///// This is a suitable replacement for a specific "order close", i.e. allowing ///// you to reverse a specific previous execution on this position. ///// </summary> ///// <param name="orderInfo"></param> ///// <param name="allowExistingActiveOrdersManipulation">Is the operation allowed to close a matching existing order, or should we always open a new one. This is suitable for Active orders brokers, that dissallow hedged orders at the same time.</param> ///// <returns></returns> //public virtual string ExecuteMarketReverse(PositionExecutionInfo orderInfo, decimal? slippage, TimeSpan timeOut, bool manipulateExistingOrders, // out PositionExecutionInfo newExecutionInfo, out string operationResultMessage) //{ // newExecutionInfo = PositionExecutionInfo.Empty; // if (orderInfo.IsEmpty == false && orderInfo.Result == PositionExecutionInfo.ExecutionResultEnum.Success) // { // OrderTypeEnum orderType = OrderTypeEnum.UNKNOWN; // if (orderInfo.OrderType == OrderTypeEnum.BUY_MARKET) // { // orderType = OrderTypeEnum.SELL_MARKET; // } // else if (orderInfo.OrderType == OrderTypeEnum.SELL_MARKET) // { // orderType = OrderTypeEnum.BUY_MARKET; // } // else // { // operationResultMessage = "Only market position can be reversed."; // SystemMonitor.OperationError(operationResultMessage); // return string.Empty; // } // return ExecuteMarket(orderType, (int)orderInfo.ExecutedVolume, null, slippage, null, null, timeOut, out newExecutionInfo, out operationResultMessage); // } // else // { // operationResultMessage = "Can not reverse execution info with result [" + orderInfo.Result.ToString() + "], no action taken."; // SystemMonitor.OperationError(operationResultMessage); // return string.Empty; // } //} /// <summary> /// /// </summary> protected virtual bool OnExecuteMarketBalanced(ISourceOrderExecution provider, int volumeModification, decimal?desiredPrice, decimal?slippage, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { OrderTypeEnum orderType = OrderTypeEnum.BUY_MARKET; if (volumeModification < 0) { orderType = OrderTypeEnum.SELL_MARKET; } return(string.IsNullOrEmpty(ExecuteMarket(orderType, Math.Abs(volumeModification), desiredPrice, slippage, null, null, timeOut, out executionInfo, out operationResultMessage)) == false); }
/// <summary> /// Places and tries to execute a market order synchronously. Since it might be a modification of an /// existing active order, no specific order Id is returned - instead a bool indicating operation result. /// </summary> /// <param name="manipulateExistingOrders">[where applicable] Is the operation allowed to close a matching existing order, or should we always open a new one. This is suitable for Active orders brokers, that dissallow hedged orders at the same time.</param> public string ExecuteMarket(OrderTypeEnum orderType, int volume, decimal? price, decimal? slippage, decimal? takeProfit, decimal? stopLoss, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { operationResultMessage = string.Empty; executionInfo = PositionExecutionInfo.Empty; ISourceOrderExecution provider = _orderProvider; if (provider == null || provider.DefaultAccount == null) { operationResultMessage = "Position not properly initialized."; return string.Empty; } // Trace pre-execution info. string traceMessage = string.Format("Submit Type[{0}] Volume [{1}] Price [{2}] Slippage [{3}] TP [{4}] SL [{5}] TimeOut [{6}]", orderType.ToString(), volume.ToString(), GeneralHelper.ToString(price), GeneralHelper.ToString(slippage), GeneralHelper.ToString(takeProfit), GeneralHelper.ToString(stopLoss), timeOut.ToString()); traceMessage += GenerateConditionsInfo(); TracerHelper.Trace(_tracer, traceMessage, TracerItem.PriorityEnum.High); _isProcessing = true; string result = OnExecuteMarket(provider, orderType, volume, price, slippage, takeProfit, stopLoss, timeOut, out executionInfo, out operationResultMessage); SystemMonitor.CheckError(result == executionInfo.ExecutionId, operationResultMessage); _isProcessing = false; return result; }
/// <summary> /// /// </summary> protected override bool OnExecuteMarketBalanced(ISourceOrderExecution provider, int volumeModification, decimal? desiredPrice, decimal? slippage, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { if (_manipulateExistingOrders == false) { return base.OnExecuteMarketBalanced(provider, volumeModification, desiredPrice, slippage, timeOut, out executionInfo, out operationResultMessage); } OrderTypeEnum orderType = OrderTypeEnum.BUY_MARKET; if (volumeModification < 0) { orderType = OrderTypeEnum.SELL_MARKET; volumeModification = Math.Abs(volumeModification); } executionInfo = PositionExecutionInfo.Empty; int originalVolumeModification = volumeModification; List<KeyValuePair<double, decimal>> closePrices = new List<KeyValuePair<double, decimal>>(); bool suitableOrdersAvailable; ActiveOrder orderSelected = ObtainManipulationOrder(provider, GetReverseOrderType(orderType), Math.Abs(originalVolumeModification), out suitableOrdersAvailable); if (orderSelected != null && volumeModification > 0) { if (volumeModification >= orderSelected.CurrentVolume) { int orderVolume = orderSelected.CurrentVolume; if (orderSelected.Close(slippage, null)) { volumeModification -= orderVolume; if (orderSelected.ClosePrice.HasValue) { closePrices.Add(new KeyValuePair<double, decimal>(orderVolume, orderSelected.ClosePrice.Value)); } else { SystemMonitor.Error("Order [{" + orderSelected.Id + "}] closed but close price not assigned."); } } else { ReleaseManipulationOrder(orderSelected); operationResultMessage = "Failed to close corresponding reverse active order."; return false; } } else { if (orderSelected.DecreaseVolume(volumeModification, slippage, null)) { volumeModification = 0; } } ReleaseManipulationOrder(orderSelected); orderSelected = null; } if (suitableOrdersAvailable && volumeModification > 0 && originalVolumeModification == volumeModification) {// Complete failure to close anything, and there are some suitable. executionInfo = PositionExecutionInfo.Empty; operationResultMessage = "Suitable reverse market orders are available, but currently manipulated, so hedging rules forbid reverse orders placement at this moment."; return false; } if (volumeModification > 0) {// We need to execute one more in the reverse direction. PositionExecutionInfo marketExecutionInfo; string tmp; string executionResult = ExecuteMarket(orderType, volumeModification, null, slippage, null, null, timeOut, out marketExecutionInfo, out tmp); if (string.IsNullOrEmpty(executionResult) == false) {// Success. volumeModification -= (int)marketExecutionInfo.VolumeExecuted; if (marketExecutionInfo.ExecutedPrice.HasValue) { closePrices.Add(new KeyValuePair<double, decimal>(marketExecutionInfo.VolumeExecuted, marketExecutionInfo.ExecutedPrice.Value)); } else { SystemMonitor.Error("MarketExecutionInfo for a valid execution [{" + executionResult + "}] does not have ExecutedPrice assigned."); } } else { operationResultMessage = tmp; return false; } } // Calculate the close price, combination from the operations. decimal closePrice = 0; double totalVolume = 0; if (FinancialHelper.CalculateAveragePrice(closePrices, out closePrice, out totalVolume) == false) { SystemMonitor.Error("Failed to calculate average price for market balanced execution."); closePrice = 0; } if (volumeModification > 0) {// Failure. if (originalVolumeModification == volumeModification) {// Complete failure. executionInfo = PositionExecutionInfo.Empty; operationResultMessage = "Failed to execute market operation."; return false; } else {// Partial execution success. executionInfo = new PositionExecutionInfo(Guid.NewGuid().ToString(), _dataDelivery.SourceId, provider.SourceId, Symbol, orderType, closePrice, originalVolumeModification, originalVolumeModification - volumeModification, DateTime.Now, PositionExecutionInfo.ExecutionResultEnum.PartialSuccess); } } else {// Success. executionInfo = new PositionExecutionInfo(Guid.NewGuid().ToString(), _dataDelivery.SourceId, provider.SourceId, Symbol, orderType, closePrice, originalVolumeModification, originalVolumeModification, DateTime.Now, PositionExecutionInfo.ExecutionResultEnum.Success); } operationResultMessage = string.Empty; return true; }
/// <summary> /// This may contain a few operations on active orders, in order to match the rule "no opposing active orders" /// </summary> public virtual string ExecuteMarketBalanced(int volumeModification, decimal? desiredPrice, decimal? slippage, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { executionInfo = PositionExecutionInfo.Empty; ISourceOrderExecution provider = _orderProvider; if (provider == null || provider.DefaultAccount == null) { operationResultMessage = "Position not properly initialized."; return string.Empty; } // Trace pre-execution info. string traceMessage = string.Format("Submit Volume Modification [{0}] Price [{1}] Slippage [{2}] TimeOut [{3}]", volumeModification.ToString(), GeneralHelper.ToString(desiredPrice), GeneralHelper.ToString(slippage), timeOut.ToString()); traceMessage += GenerateConditionsInfo(); TracerHelper.Trace(_tracer, traceMessage, TracerItem.PriorityEnum.High); if (OnExecuteMarketBalanced(provider, volumeModification, desiredPrice, slippage, timeOut, out executionInfo, out operationResultMessage)) { return Guid.NewGuid().ToString(); } return string.Empty; }
/// <summary> /// /// </summary> protected override string OnExecuteMarket(ISourceOrderExecution provider, OrderTypeEnum orderType, int volume, decimal?price, decimal?slippage, decimal?takeProfit, decimal?stopLoss, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { SystemMonitor.CheckError(provider.SupportsActiveOrderManagement, "Wrong position type for this provider."); executionInfo = PositionExecutionInfo.Empty; IQuoteProvider quoteProvider = _manager.ObtainQuoteProvider(_dataDelivery.SourceId, Symbol); if (quoteProvider == null) { operationResultMessage = "Failed to establish quote provider for [" + _dataDelivery.SourceId.Name + ", " + Symbol.Name + "]."; SystemMonitor.Error(operationResultMessage); return(string.Empty); } price = ProcessPrice(quoteProvider, orderType, price); // New order shall be created. ActiveOrder order = new ActiveOrder(_manager, provider, quoteProvider, _dataDelivery.SourceId, Symbol, true); OrderInfo?infoReference; // Using the extended operationTimeOut to 40 seconds. bool result = provider.SynchronousExecute(provider.DefaultAccount.Info, order, _info.Symbol, orderType, volume, slippage, price, takeProfit, stopLoss, string.Empty, TimeSpan.FromSeconds(40), out infoReference, out operationResultMessage); if (result && infoReference.HasValue) { OrderInfo infoAssign = infoReference.Value; if (infoAssign.Type == OrderTypeEnum.UNKNOWN) { infoAssign.Type = orderType; } if (infoAssign.Volume == int.MinValue || infoAssign.Volume == int.MaxValue) {// Volume was not retrieved by integration. infoAssign.Volume = volume; } if (infoAssign.OpenPrice.HasValue) { executionInfo = new PositionExecutionInfo(infoReference.Value.Id, _dataDelivery.SourceId, provider.SourceId, Symbol, infoAssign.Type, infoAssign.OpenPrice.Value, volume, volume, infoAssign.OpenTime, PositionExecutionInfo.ExecutionResultEnum.Success); } else { SystemMonitor.Error("Received execution result, but price not assigned."); } order.AdoptInfo(infoAssign); provider.TradeEntities.AddOrder(order); return(infoReference.Value.Id); } return(string.Empty); }
/// <summary> /// /// </summary> protected override bool OnExecuteMarketBalanced(ISourceOrderExecution provider, int volumeModification, decimal?desiredPrice, decimal?slippage, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { if (_manipulateExistingOrders == false) { return(base.OnExecuteMarketBalanced(provider, volumeModification, desiredPrice, slippage, timeOut, out executionInfo, out operationResultMessage)); } OrderTypeEnum orderType = OrderTypeEnum.BUY_MARKET; if (volumeModification < 0) { orderType = OrderTypeEnum.SELL_MARKET; volumeModification = Math.Abs(volumeModification); } executionInfo = PositionExecutionInfo.Empty; int originalVolumeModification = volumeModification; List <KeyValuePair <double, decimal> > closePrices = new List <KeyValuePair <double, decimal> >(); bool suitableOrdersAvailable; ActiveOrder orderSelected = ObtainManipulationOrder(provider, GetReverseOrderType(orderType), Math.Abs(originalVolumeModification), out suitableOrdersAvailable); if (orderSelected != null && volumeModification > 0) { if (volumeModification >= orderSelected.CurrentVolume) { int orderVolume = orderSelected.CurrentVolume; if (orderSelected.Close(slippage, null)) { volumeModification -= orderVolume; if (orderSelected.ClosePrice.HasValue) { closePrices.Add(new KeyValuePair <double, decimal>(orderVolume, orderSelected.ClosePrice.Value)); } else { SystemMonitor.Error("Order [{" + orderSelected.Id + "}] closed but close price not assigned."); } } else { ReleaseManipulationOrder(orderSelected); operationResultMessage = "Failed to close corresponding reverse active order."; return(false); } } else { if (orderSelected.DecreaseVolume(volumeModification, slippage, null)) { volumeModification = 0; } } ReleaseManipulationOrder(orderSelected); orderSelected = null; } if (suitableOrdersAvailable && volumeModification > 0 && originalVolumeModification == volumeModification) {// Complete failure to close anything, and there are some suitable. executionInfo = PositionExecutionInfo.Empty; operationResultMessage = "Suitable reverse market orders are available, but currently manipulated, so hedging rules forbid reverse orders placement at this moment."; return(false); } if (volumeModification > 0) {// We need to execute one more in the reverse direction. PositionExecutionInfo marketExecutionInfo; string tmp; string executionResult = ExecuteMarket(orderType, volumeModification, null, slippage, null, null, timeOut, out marketExecutionInfo, out tmp); if (string.IsNullOrEmpty(executionResult) == false) {// Success. volumeModification -= (int)marketExecutionInfo.VolumeExecuted; if (marketExecutionInfo.ExecutedPrice.HasValue) { closePrices.Add(new KeyValuePair <double, decimal>(marketExecutionInfo.VolumeExecuted, marketExecutionInfo.ExecutedPrice.Value)); } else { SystemMonitor.Error("MarketExecutionInfo for a valid execution [{" + executionResult + "}] does not have ExecutedPrice assigned."); } } else { operationResultMessage = tmp; return(false); } } // Calculate the close price, combination from the operations. decimal closePrice = 0; double totalVolume = 0; if (FinancialHelper.CalculateAveragePrice(closePrices, out closePrice, out totalVolume) == false) { SystemMonitor.Error("Failed to calculate average price for market balanced execution."); closePrice = 0; } if (volumeModification > 0) { // Failure. if (originalVolumeModification == volumeModification) { // Complete failure. executionInfo = PositionExecutionInfo.Empty; operationResultMessage = "Failed to execute market operation."; return(false); } else {// Partial execution success. executionInfo = new PositionExecutionInfo(Guid.NewGuid().ToString(), _dataDelivery.SourceId, provider.SourceId, Symbol, orderType, closePrice, originalVolumeModification, originalVolumeModification - volumeModification, DateTime.Now, PositionExecutionInfo.ExecutionResultEnum.PartialSuccess); } } else {// Success. executionInfo = new PositionExecutionInfo(Guid.NewGuid().ToString(), _dataDelivery.SourceId, provider.SourceId, Symbol, orderType, closePrice, originalVolumeModification, originalVolumeModification, DateTime.Now, PositionExecutionInfo.ExecutionResultEnum.Success); } operationResultMessage = string.Empty; return(true); }
/// <summary> /// Places and tries to execute a market order synchronously. Since it might be a modification of an /// existing active order, no specific order Id is returned - instead a bool indicating operation result. /// </summary> /// <param name="manipulateExistingOrders">[where applicable] Is the operation allowed to close a matching existing order, or should we always open a new one. This is suitable for Active orders brokers, that dissallow hedged orders at the same time.</param> public string ExecuteMarket(OrderTypeEnum orderType, int volume, decimal?price, decimal?slippage, decimal?takeProfit, decimal?stopLoss, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { //TracerHelper.TraceEntry(); operationResultMessage = string.Empty; executionInfo = PositionExecutionInfo.Empty; ISourceOrderExecution provider = _provider; if (provider == null || provider.DefaultAccount == null) { operationResultMessage = "Position not properly initialized."; return(string.Empty); } _isProcessing = true; string result = OnExecuteMarket(provider, orderType, volume, price, slippage, takeProfit, stopLoss, timeOut, out executionInfo, out operationResultMessage); SystemMonitor.CheckError(result == executionInfo.ExecutionId, operationResultMessage); _isProcessing = false; return(result); }
/// <summary> /// /// </summary> protected abstract string OnExecuteMarket(ISourceOrderExecution provider, OrderTypeEnum orderType, int volume, decimal? price, decimal? slippage, decimal? takeProfit, decimal? stopLoss, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage);
/// <summary> /// This may contain a few operations on active orders, in order to match the rule "no opposing active orders" /// </summary> public virtual string ExecuteMarketBalanced(int volumeModification, decimal? desiredPrice, decimal? slippage, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { executionInfo = PositionExecutionInfo.Empty; ISourceOrderExecution provider = _provider; if (provider == null || provider.DefaultAccount == null) { operationResultMessage = "Position not properly initialized."; return string.Empty; } if (OnExecuteMarketBalanced(provider, volumeModification, desiredPrice, slippage, timeOut, out executionInfo, out operationResultMessage)) { return Guid.NewGuid().ToString(); } return string.Empty; }
/// <summary> /// Places and tries to execute a market order synchronously. Since it might be a modification of an /// existing active order, no specific order Id is returned - instead a bool indicating operation result. /// </summary> /// <param name="manipulateExistingOrders">[where applicable] Is the operation allowed to close a matching existing order, or should we always open a new one. This is suitable for Active orders brokers, that dissallow hedged orders at the same time.</param> public string ExecuteMarket(OrderTypeEnum orderType, int volume, decimal? price, decimal? slippage, decimal? takeProfit, decimal? stopLoss, TimeSpan timeOut, out PositionExecutionInfo executionInfo, out string operationResultMessage) { //TracerHelper.TraceEntry(); operationResultMessage = string.Empty; executionInfo = PositionExecutionInfo.Empty; ISourceOrderExecution provider = _provider; if (provider == null || provider.DefaultAccount == null) { operationResultMessage = "Position not properly initialized."; return string.Empty; } _isProcessing = true; string result = OnExecuteMarket(provider, orderType, volume, price, slippage, takeProfit, stopLoss, timeOut, out executionInfo, out operationResultMessage); SystemMonitor.CheckError(result == executionInfo.ExecutionId, operationResultMessage); _isProcessing = false; return result; }
/// <summary> /// /// </summary> public string ExecuteMarketBalancedClose(int? closeVolume, TimeSpan timeOut, out PositionExecutionInfo executionResult, out string operationResultMessage) { operationResultMessage = string.Empty; executionResult = PositionExecutionInfo.Empty; ISourceOrderExecution provider = _orderProvider; if (provider == null || provider.DefaultAccount == null) { operationResultMessage = "Position not initialized."; return string.Empty; } if (Volume == 0) { operationResultMessage = "Position has no open volume (amount)."; return string.Empty; } if (closeVolume.HasValue == false) { closeVolume = -(int)Volume; } else if (Volume > 0) {// Reverse of direction needed, since we make it directional. closeVolume = -closeVolume.Value; } if (Math.Abs(closeVolume.Value) > Math.Abs(Volume)) { operationResultMessage = "Volume (amount) to close too big."; return string.Empty; } return ExecuteMarketBalanced(closeVolume.Value, null, null, timeOut, out executionResult, out operationResultMessage); }