/// <summary> /// /// </summary> /// <param name="orderTransaction"></param> /// <param name="thrust"></param> /// <param name="retracement"></param> /// <returns></returns> protected virtual async Task UpdateEntryOrder(StrategyTransaction orderTransaction, Chart chart, Thrust thrust) { long orderId = Convert.ToInt64(orderTransaction.BrokerTransactionID); MarketMinerOrder currentOrder = Orders.FirstOrDefault(o => o.id == orderId) as MarketMinerOrder; string side = thrust.Side; Tuple <double, double, double> orderPrices = GetOrderPrices(chart.HistoricBidAskSpread, side, thrust); double entryPrice = orderPrices.Item1; double stopLossPrice = orderPrices.Item2; double takeProfitPrice = orderPrices.Item3; // round and review int places = ((FibonacciRetracement)thrust.Study).LevelPlaces(); bool updateOrder = false; if (currentOrder == null) { updateOrder = true; } else { if (Math.Round(entryPrice, places) != currentOrder.price) { updateOrder = true; } if (Math.Round(stopLossPrice, places) != currentOrder.stopLoss) { updateOrder = true; } if (Math.Round(takeProfitPrice, places) != currentOrder.takeProfit) { updateOrder = true; } } if (updateOrder) { int tradeUnits = await TradeUnitsCapacity(thrust.Instrument, entryPrice, stopLossPrice, true); // order size should never increase tradeUnits = currentOrder != null?Math.Min(currentOrder.units, tradeUnits) : tradeUnits; if (tradeUnits > 0) { // 12 hours for now .. how should this change? string expiry = MAOE.Utilities.GetTimeAsXmlSerializedUtc(DateTime.UtcNow.AddHours(12)); // create patch var patchData = new Dictionary <string, string> { { "units", tradeUnits.ToString() }, { "expiry", expiry }, { "price", Math.Round(entryPrice, places).ToString() }, { "stopLoss", Math.Round(stopLossPrice, places).ToString() }, { "takeProfit", Math.Round(takeProfitPrice, places).ToString() } }; // what if the fill happens just as execution arrives here? // this bit should somehow affirm that the order remains unfilled Order updatedOrder = await Rest.PatchOrderAsync(_accountId, orderId, patchData); if (updatedOrder != null) { MarketMinerOrder mmUpdatedOrder = new MarketMinerOrder(updatedOrder); mmUpdatedOrder.SignalID = thrust.SignalID; mmUpdatedOrder.StrategyTransactionID = orderTransaction.StrategyTransactionID; AddOrUpdateAlgorithmOrder(mmUpdatedOrder); DateTime transactionTime = Convert.ToDateTime(updatedOrder.time).ToUniversalTime(); thrust.SetOrUpdatePrices(entryPrice, takeProfitPrice, stopLossPrice, places, transactionTime); } } else { thrust.Active = false; // cancel the order await Rest.DeleteOrderAsync(_accountId, orderId); // clear the chart PurgeThrust(chart, thrust); string missedTradeReason = Utilities.GetMissedTradeReason(tradeUnits); AddAlgorithmMessage(string.Format("Missed trade: {0} for signalId: {1}", missedTradeReason, thrust.SignalID), true, TraceEventType.Information); } } }
protected async Task <bool> UpdateOrdersAndTrades() { AddAlgorithmMessage("Updating instance orders and trades ...", false, TraceEventType.Information); short orderCount = 0; short tradeCount = 0; MCE.Signal[] signals = await SubscriptionCaller.Instance().GetActiveSignalsByTypeAsync(MACC.Constants.SignalType.Thrust); foreach (MCE.Signal signal in signals) { if (signal.StrategyTransactionID.HasValue) { IEnumerable <StrategyTransaction> transactions; StrategyTransaction orderTransaction, tradeTransaction, exitTransaction; // get transaction collection from db int orderTransactionID = signal.StrategyTransactionID.Value; transactions = StrategyCaller.Instance().GetStrategyTransactionsCollectionAsync(orderTransactionID).Result; transactions = transactions.Where(t => t.StrategyID == _strategy.StrategyID); transactions = transactions.OrderBy(t => t.BrokerTransactionID); orderTransaction = transactions.FirstOrDefault(t => t.StrategyTransactionID == orderTransactionID); tradeTransaction = transactions.FirstOrDefault(t => t.Type == MACC.Constants.TransactionTypes.OrderFilled); exitTransaction = transactions.FirstOrDefault(t => t.BrokerTradeID != null && t.Type != MACC.Constants.TransactionTypes.TradeUpdate); if (exitTransaction != null) { signal.Active = false; SubscriptionCaller.Instance().UpdateSignalAsync(signal); continue; } if (tradeTransaction != null) { tradeCount++; long tradeId = Convert.ToInt64(tradeTransaction.BrokerTransactionID); TradeData oandaTrade = await Rest.GetTradeDetailsAsync(_accountId, tradeId); MarketMinerTrade mmTrade = new MarketMinerTrade(oandaTrade) { SignalID = signal.SignalID, StrategyTransactionID = signal.StrategyTransactionID, Closed = exitTransaction != null }; AddOrUpdateAlgorithmTrade(mmTrade); continue; } if (orderTransaction != null) { orderCount++; long orderId = Convert.ToInt64(orderTransaction.BrokerTransactionID); Order oandaOrder = await Rest.GetOrderDetailsAsync(_accountId, orderId); MarketMinerOrder mmOrder = new MarketMinerOrder(oandaOrder) { SignalID = signal.SignalID, StrategyTransactionID = signal.StrategyTransactionID, Filled = tradeTransaction != null, Cancelled = tradeTransaction != null }; AddOrUpdateAlgorithmOrder(mmOrder); } } } AddAlgorithmMessage(string.Format("{0} open orders updated.", orderCount), false, TraceEventType.Information); AddAlgorithmMessage(string.Format("{0} open trades updated.", tradeCount), false, TraceEventType.Information); return(true); }
/// <summary> /// /// </summary> /// <param name="signal"></param> /// <param name="instrument"></param> /// <param name="retracement"></param> /// <returns></returns> protected virtual async Task <int> CreateEntryOrder(MCE.Signal signal, Chart chart, Thrust thrust) { StrategyTransaction transaction = null; Tuple <double, double, double> orderPrices = GetOrderPrices(chart.HistoricBidAskSpread, signal.Side, thrust); double entryPrice = orderPrices.Item1; double stopLossPrice = orderPrices.Item2; double takeProfitPrice = orderPrices.Item3; int tradeUnits = await TradeUnitsCapacity(chart.Instrument, entryPrice, stopLossPrice); if (tradeUnits > 0) { // 12 hours for now .. how should this change? .. read from metaSetting? string expiry = MAOE.Utilities.GetTimeAsXmlSerializedUtc(DateTime.UtcNow.AddHours(12)); string type = "limit"; string side = signal.Side == MACC.Constants.SignalSide.Buy ? "buy" : "sell"; int places = ((FibonacciRetracement)thrust.Study).LevelPlaces(); // create order var orderData = new Dictionary <string, string> { { "instrument", chart.Instrument }, { "units", tradeUnits.ToString() }, { "side", side }, { "type", type }, { "expiry", expiry }, { "price", Math.Round(entryPrice, places).ToString() }, { "stopLoss", Math.Round(stopLossPrice, places).ToString() }, { "takeProfit", Math.Round(takeProfitPrice, places).ToString() } }; PostOrderResponse response = await PlaceLimitOrder(orderData); if (response.orderOpened != null && response.orderOpened.id > 0) { MarketMinerOrder orderOpened = new MarketMinerOrder(response.orderOpened); orderOpened.SignalID = signal.SignalID; transaction = CreateEntryTransaction(chart.Instrument, orderOpened.side, response.time, type, response.price.GetValueOrDefault(), orderOpened.takeProfit, orderOpened.stopLoss, orderOpened.id.ToString()); transaction = await StrategyCaller.Instance().SaveStrategyTransactionAsync(transaction, MarketMiner.Common.Constants.Brokers.OANDA); orderOpened.StrategyTransactionID = transaction.StrategyTransactionID; // add entry trans id to the signal signal.StrategyTransactionID = transaction.StrategyTransactionID; await SubscriptionCaller.Instance().UpdateSignalAsync(signal); AddOrUpdateAlgorithmOrder(orderOpened); DateTime transactionTime = Convert.ToDateTime(response.time).ToUniversalTime(); thrust.SetOrUpdatePrices(entryPrice, takeProfitPrice, stopLossPrice, places, transactionTime); } } else { string missedTradeReason = Utilities.GetMissedTradeReason(tradeUnits); AddAlgorithmMessage(string.Format("Missed trade: {0} for signalId: {1}", missedTradeReason, signal.SignalID), true, TraceEventType.Information); } return(transaction == null ? 0 : transaction.StrategyTransactionID); }