/// <summary> /// Default market fill model for the base security class. Fills at the last traded price. /// </summary> /// <param name="asset">Security asset we're filling</param> /// <param name="order">Order packet to model</param> /// <returns>Order fill information detailing the average price and quantity filled.</returns> /// <seealso cref="SecurityTransactionModel.StopMarketFill"/> /// <seealso cref="SecurityTransactionModel.LimitFill"/> public virtual OrderEvent MarketFill(Security asset, MarketOrder order) { //Default order event to return. var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone); var fill = new OrderEvent(order, utcTime, 0); if (order.Status == OrderStatus.Canceled) return fill; // make sure the exchange is open before filling if (!IsExchangeOpen(asset)) return fill; //Order [fill]price for a market order model is the current security price fill.FillPrice = asset.Price; fill.Status = OrderStatus.Filled; //Calculate the model slippage: e.g. 0.01c var slip = asset.SlippageModel.GetSlippageApproximation(asset, order); //Apply slippage switch (order.Direction) { case OrderDirection.Buy: fill.FillPrice += slip; break; case OrderDirection.Sell: fill.FillPrice -= slip; break; } // assume the order completely filled if (fill.Status == OrderStatus.Filled) { fill.FillQuantity = order.Quantity; fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order); } return fill; }
private void ClosedOrdersWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { efficiency.closedDeals = (List <MarketOrder>)e.Result; if (efficiency.closedDeals == null) { return; } var closedDeals = efficiency.closedDeals.ToList(); // суммарная закрытая сделка MarketOrder sumClosed = null; if (closedDeals.Count > 0) { var sumVolume = closedDeals.Sum(d => d.Volume * d.Side); sumClosed = new MarketOrder { Symbol = "Сумм", Volume = Math.Abs(sumVolume), Side = Math.Sign(sumVolume), ResultDepo = closedDeals.Sum(d => d.ResultDepo), TimeEnter = closedDeals.Min(d => d.TimeEnter) }; closedDeals.Add(sumClosed); } closedOrdersFastGrid.DataBind(closedDeals); if (sumClosed != null) { var lastRow = closedOrdersFastGrid.rows.First(r => r.ValueObject == sumClosed); lastRow.anchor = FastRow.AnchorPosition.AnchorBottom; } closedOrdersLoaded = true; closedOrdersStandByControl.IsShown = false; closedOrdersStandByControl.Hide(); closedOrdersFastGrid.Show(); // обновляем статистику RebindStatisticsGrid(); // статистика по валютам try { // ReSharper disable AssignNullToNotNullAttribute var blank = new DealCountBySymbol(); countByTickerChart.Series[0].Points.DataBind(PerformerStatistic.GetDealCountBySymbol(efficiency), blank.Property(p => p.Title), blank.Property(p => p.DealCount), null); // ReSharper restore AssignNullToNotNullAttribute } catch { } countByTickerStandByControl.IsShown = false; countByTickerStandByControl.Hide(); countByTickerChart.Show(); // строим диаграмму CreateDiagram(); profitByMonthStandByControl.IsShown = false; profitByMonthStandByControl.Hide(); profitByMonthChart.Show(); if (ClosedDealsLoaded != null) { ClosedDealsLoaded(this, new EventArgs()); } }
/// <summary> /// Gets all orders not yet closed /// </summary> /// <returns></returns> public override List <Orders.Order> GetOpenOrders() { var list = new List <Order>(); try { var req = new RestRequest("/orders?status=open&status=pending", Method.GET); GetAuthenticationToken(req); var response = RestClient.Execute(req); if (response != null) { var orders = JsonConvert.DeserializeObject <Messages.Order[]>(response.Content); foreach (var item in orders) { Order order = null; if (item.Type == "market") { order = new MarketOrder { Price = item.Price }; } else if (item.Type == "limit") { order = new LimitOrder { LimitPrice = item.Price }; } else if (item.Type == "stop") { order = new StopMarketOrder { StopPrice = item.Price }; } else { Log.Error("GDAXBrokerage.GetOpenOrders: Unsupported order type returned from brokerage" + item.Type); continue; } order.Quantity = item.Side == "sell" ? -item.Size : item.Size; order.BrokerId = new List <string> { item.Id.ToString() }; order.Symbol = ConvertProductId(item.ProductId); order.Time = DateTime.UtcNow; order.Status = ConvertOrderStatus(item); order.Price = item.Price; list.Add(order); } } } catch (Exception) { throw; } foreach (Order item in list) { if (item.Status.IsOpen()) { var cached = this.CachedOrderIDs.Where(c => c.Value.BrokerId.Contains(item.BrokerId.First())); if (cached.Any()) { this.CachedOrderIDs[cached.First().Key] = item; } } } return(list); }
/// <summary> /// Gets all orders not yet closed /// </summary> /// <returns></returns> public override List <Order> GetOpenOrders() { var endpoint = GetEndpoint("auth/r/orders"); var request = new RestRequest(endpoint, Method.POST); var parameters = new JsonObject(); request.AddJsonBody(parameters.ToString()); SignRequest(request, endpoint, parameters); var response = ExecuteRestRequest(request); if (response.StatusCode != HttpStatusCode.OK) { throw new Exception($"BitfinexBrokerage.GetOpenOrders: request failed: [{(int)response.StatusCode}] {response.StatusDescription}, Content: {response.Content}, ErrorMessage: {response.ErrorMessage}"); } var orders = JsonConvert.DeserializeObject <Messages.Order[]>(response.Content) .Where(OrderFilter(_algorithm.BrokerageModel.AccountType)); var list = new List <Order>(); foreach (var item in orders) { Order order; if (item.Type.Replace("EXCHANGE", "").Trim() == "MARKET") { order = new MarketOrder { Price = item.Price }; } else if (item.Type.Replace("EXCHANGE", "").Trim() == "LIMIT") { order = new LimitOrder { LimitPrice = item.Price }; } else if (item.Type.Replace("EXCHANGE", "").Trim() == "STOP") { order = new StopMarketOrder { StopPrice = item.Price }; } else { OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Error, (int)response.StatusCode, "BitfinexBrokerage.GetOpenOrders: Unsupported order type returned from brokerage: " + item.Type)); continue; } order.Quantity = item.Amount; order.BrokerId = new List <string> { item.Id.ToStringInvariant() }; order.Symbol = _symbolMapper.GetLeanSymbol(item.Symbol, SecurityType.Crypto, Market.Bitfinex); order.Time = Time.UnixMillisecondTimeStampToDateTime(item.MtsCreate); order.Status = ConvertOrderStatus(item); order.Price = item.Price; list.Add(order); } foreach (var item in list) { if (item.Status.IsOpen()) { var cached = CachedOrderIDs .FirstOrDefault(c => c.Value.BrokerId.Contains(item.BrokerId.First())); if (cached.Value != null) { CachedOrderIDs[cached.Key] = item; } } } return(list); }
public PyDataType CancelCharOrder(PyInteger orderID, PyInteger regionID, CallInformation call) { int callerCharacterID = call.Client.EnsureCharacterIsSelected(); Character character = this.ItemFactory.GetItem <Character>(callerCharacterID); using MySqlConnection connection = this.DB.AcquireMarketLock(); try { MarketOrder order = this.DB.GetOrderById(connection, orderID); if (order.CharacterID != callerCharacterID) { throw new MktOrderDidNotMatch(); } long currentTime = DateTime.UtcNow.ToFileTimeUtc(); // check for timers, no changes in less than 5 minutes if (currentTime < order.Issued + TimeSpan.TicksPerSecond * this.NodeContainer.Constants[Constants.mktModificationDelay]) { throw new MktOrderDelay((order.Issued + TimeSpan.TicksPerSecond * this.NodeContainer.Constants[Constants.mktModificationDelay]) - currentTime); } // check for escrow if (order.Escrow > 0.0 && order.Bid == TransactionType.Buy) { using Wallet wallet = this.WalletManager.AcquireWallet(character.ID, 1000); { wallet.CreateJournalRecord(MarketReference.MarketEscrow, null, null, order.Escrow); } } if (order.Bid == TransactionType.Sell) { // create the new item that will be used by the player ItemEntity item = this.ItemFactory.CreateSimpleItem( this.TypeManager[order.TypeID], character.ID, order.LocationID, Flags.Hangar, order.UnitsLeft ); // immediately unload it, if it has to be loaded the OnItemUpdate notification will take care of that this.ItemFactory.UnloadItem(item); // check what node this item should be loaded at long stationNode = this.SystemManager.GetNodeStationBelongsTo(order.LocationID); if (stationNode == 0 || this.SystemManager.StationBelongsToUs(order.LocationID) == true) { this.NotificationManager.NotifyCharacter(character.ID, Notifications.Client.Inventory.OnItemChange.BuildLocationChange(item, this.ItemFactory.LocationMarket.ID)); } else { this.NotificationManager.NotifyNode(stationNode, OnItemChange.BuildLocationChange(item.ID, this.ItemFactory.LocationMarket.ID, order.LocationID)); } } // finally remove the order this.DB.RemoveOrder(connection, order.OrderID); // send a OnOwnOrderChange notification call.Client.NotifyMultiEvent(new OnOwnOrderChanged(order.TypeID, "Removed")); } finally { this.DB.ReleaseMarketLock(connection); } return(null); }
public OrderEvent MarketFill(Security asset, MarketOrder order) { MarketFillWasCalled = true; return(orderEvent); }
/// <summary> /// Automatically place an order which will set the holdings to between 100% or -100% of *Buying Power*. /// E.g. SetHoldings("AAPL", 0.1); SetHoldings("IBM", -0.2); -> Sets portfolio as long 10% APPL and short 20% IBM /// </summary> /// <param name="symbol"> string Symbol indexer</param> /// <param name="percentage">decimal fraction of portfolio to set stock</param> /// <param name="liquidateExistingHoldings">bool flag to clean all existing holdings before setting new faction.</param> /// <param name="tag">Tag the order with a short string.</param> /// <seealso cref="MarketOrder"/> public void SetHoldings(string symbol, decimal percentage, bool liquidateExistingHoldings = false, string tag = "") { //Error checks: if (!Portfolio.ContainsKey(symbol)) { Error(symbol.ToUpper() + " not found in portfolio. Request this data when initializing the algorithm."); return; } //Range check values: if (percentage > 1) { percentage = 1; } if (percentage < -1) { percentage = -1; } //If they triggered a liquidate if (liquidateExistingHoldings) { foreach (var holdingSymbol in Portfolio.Keys) { if (holdingSymbol != symbol && Portfolio[holdingSymbol].AbsoluteQuantity > 0) { //Go through all existing holdings [synchronously], market order the inverse quantity: Order(holdingSymbol, -Portfolio[holdingSymbol].Quantity); } } } var security = Securities[symbol]; // compute the remaining margin for this security var direction = percentage > 0 ? OrderDirection.Buy : OrderDirection.Sell; // compute an estimate of the buying power for this security incorporating the implied leverage var marginRemaining = Math.Abs(percentage) * security.MarginModel.GetMarginRemaining(Portfolio, security, direction); // // Since we can't assume anything about the fee structure and the relative size of fees in // relation to the order size we need to perform some root finding. In general we'll only need // a two loops to compute a correct value. Some exotic fee structures may require more searching. // // compute the margin required for a single share int quantity = 1; var marketOrder = new MarketOrder(symbol, quantity, Time, type: security.Type) { Price = security.Price }; var marginRequiredForSingleShare = security.MarginModel.GetInitialMarginRequiredForOrder(security, marketOrder); // we want marginRequired to end up between this and marginRemaining var marginRequiredLowerThreshold = marginRemaining - marginRequiredForSingleShare; // iterate until we get a decent estimate, max out at 10 loops. int loops = 0; var marginRequired = marginRequiredForSingleShare; while (marginRequired > marginRemaining || marginRequired < marginRequiredLowerThreshold) { var marginPerShare = marginRequired / quantity; quantity = (int)Math.Truncate(marginRemaining / marginPerShare); marketOrder.Quantity = quantity; marginRequired = security.MarginModel.GetInitialMarginRequiredForOrder(security, marketOrder); // no need to iterate longer than 10 if (++loops > 10) { break; } } // nothing to change if (quantity == 0) { return; } // adjust for going short if (direction == OrderDirection.Sell) { quantity *= -1; } MarketOrder(symbol, quantity, false, tag); }
public Order SellOrder(Instrument instrument, double qty, string text) { SingleOrder singleOrder = new MarketOrder(instrument.instrument, Side.Sell, qty, text); singleOrder.Strategy = this.strategyName; Order order = new Order(singleOrder); order.Portfolio = this.portfolio; Map.OQ_SQ_Order[order] = singleOrder; Map.SQ_OQ_Order[singleOrder] = order; return order; }
public void GetAllByPortfolioEntry_Returns_Correct_Orders() { // fixture unique to this test var marketOrderRepositoryFixture = new SqlKataMarketOrderRepositoryFixture(); // arrange var marketOrder1 = new MarketOrder(new Decimal(10000.39), 10, new Decimal(1.1), DateTime.Now, true, PortfolioEntryId: marketOrderRepositoryFixture.DefaultPortfolioEntryId); var marketOrder2 = new MarketOrder(new Decimal(11000.39), 11, new Decimal(1.2), DateTime.Now.Subtract(TimeSpan.FromSeconds(3600)), true, PortfolioEntryId: marketOrderRepositoryFixture.DefaultPortfolioEntryId); var marketOrder3 = new MarketOrder(new Decimal(12000.39), 12, new Decimal(1.3), DateTime.Now.Subtract(TimeSpan.FromDays(30)), false, PortfolioEntryId: marketOrderRepositoryFixture.DefaultPortfolioEntryId); var marketOrder4 = new MarketOrder(new Decimal(12005.39), 15, new Decimal(12), DateTime.Now.Subtract(TimeSpan.FromDays(11)), false, PortfolioEntryId: marketOrderRepositoryFixture.SecondaryPortfolioEntryId); var marketOrder5 = new MarketOrder(new Decimal(12006.39), 16, new Decimal(1.5), DateTime.Now.Subtract(TimeSpan.FromDays(39)), false, PortfolioEntryId: marketOrderRepositoryFixture.SecondaryPortfolioEntryId); // act var presumablyEmptyList = marketOrderRepositoryFixture.MarketOrderRepository.GetAllByPortfolioEntryId(marketOrderRepositoryFixture .DefaultPortfolioEntryId); var presumablyEmptyList2 = marketOrderRepositoryFixture.MarketOrderRepository.GetAllByPortfolioEntryId( marketOrderRepositoryFixture.SecondaryPortfolioEntryId); marketOrder1 = marketOrder1 with { Id = marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder1) }; marketOrder2 = marketOrder2 with { Id = marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder2) }; marketOrder3 = marketOrder3 with { Id = marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder3) }; marketOrder4 = marketOrder4 with { Id = marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder4) }; marketOrder5 = marketOrder5 with { Id = marketOrderRepositoryFixture.MarketOrderRepository.Add(marketOrder5) }; // assert var loadedPortfolios = marketOrderRepositoryFixture.MarketOrderRepository.GetAllByPortfolioEntryId(marketOrderRepositoryFixture .DefaultPortfolioEntryId); Assert.Empty(presumablyEmptyList); Assert.Empty(presumablyEmptyList2); Assert.Equal(3, loadedPortfolios.Count); Assert.Equal(new List <MarketOrder> { marketOrder1, marketOrder2, marketOrder3 }, loadedPortfolios); var loadedPortfoliosSecondary = marketOrderRepositoryFixture.MarketOrderRepository.GetAllByPortfolioEntryId(marketOrderRepositoryFixture .SecondaryPortfolioEntryId); Assert.Equal(2, loadedPortfoliosSecondary.Count); Assert.Equal(new List <MarketOrder> { marketOrder4, marketOrder5 }, loadedPortfoliosSecondary); }
public void DeserializesDecimalizedQuantity() { var expected = new MarketOrder(Symbols.BTCUSD, 0.123m, DateTime.Today); TestOrderType(expected); }
public void Run(Position initialPosition, Position finalPosition, FeeType feeType, PriceMovement priceMovement, int leverage) { //Console.WriteLine("----------"); //Console.WriteLine("PARAMETERS"); //Console.WriteLine("Initial position: " + initialPosition); //Console.WriteLine("Final position: " + finalPosition); //Console.WriteLine("Fee type: " + feeType); //Console.WriteLine("Price movement: " + priceMovement); //Console.WriteLine("Leverage: " + leverage); //Console.WriteLine("----------"); //Console.WriteLine(); var algorithm = new QCAlgorithm(); algorithm.SubscriptionManager.SetDataManager(new DataManager()); var security = algorithm.AddSecurity(_symbol.ID.SecurityType, _symbol.ID.Symbol); security.FeeModel = _feeModels[feeType]; security.SetLeverage(leverage); var buyingPowerModel = new TestSecurityMarginModel(leverage); security.BuyingPowerModel = buyingPowerModel; algorithm.SetCash(Cash); Update(security, BasePrice); decimal targetPercentage; OrderDirection orderDirection; MarketOrder order; decimal orderFee; OrderEvent fill; decimal orderQuantity; decimal freeMargin; decimal requiredMargin; if (initialPosition != Position.Zero) { targetPercentage = (decimal)initialPosition; orderDirection = initialPosition == Position.Long ? OrderDirection.Buy : OrderDirection.Sell; orderQuantity = algorithm.CalculateOrderQuantity(_symbol, targetPercentage); order = new MarketOrder(_symbol, orderQuantity, DateTime.UtcNow); freeMargin = buyingPowerModel.GetMarginRemaining(algorithm.Portfolio, security, orderDirection); requiredMargin = buyingPowerModel.GetInitialMarginRequiredForOrder(security, order); //Console.WriteLine("Current price: " + security.Price); //Console.WriteLine("Target percentage: " + targetPercentage); //Console.WriteLine("Order direction: " + orderDirection); //Console.WriteLine("Order quantity: " + orderQuantity); //Console.WriteLine("Free margin: " + freeMargin); //Console.WriteLine("Required margin: " + requiredMargin); //Console.WriteLine(); Assert.That(Math.Abs(requiredMargin) <= freeMargin); orderFee = security.FeeModel.GetOrderFee(security, order); fill = new OrderEvent(order, DateTime.UtcNow, orderFee) { FillPrice = security.Price, FillQuantity = orderQuantity }; algorithm.Portfolio.ProcessFill(fill); //Console.WriteLine("Portfolio.Cash: " + algorithm.Portfolio.Cash); //Console.WriteLine("Portfolio.TotalPortfolioValue: " + algorithm.Portfolio.TotalPortfolioValue); //Console.WriteLine(); if (priceMovement == PriceMovement.RisingSmall) { Update(security, HighPrice); } else if (priceMovement == PriceMovement.FallingSmall) { Update(security, LowPrice); } else if (priceMovement == PriceMovement.RisingLarge) { Update(security, VeryHighPrice); } else if (priceMovement == PriceMovement.FallingLarge) { Update(security, VeryLowPrice); } } targetPercentage = (decimal)finalPosition; orderDirection = finalPosition == Position.Long || (finalPosition == Position.Zero && initialPosition == Position.Short) ? OrderDirection.Buy : OrderDirection.Sell; orderQuantity = algorithm.CalculateOrderQuantity(_symbol, targetPercentage); order = new MarketOrder(_symbol, orderQuantity, DateTime.UtcNow); freeMargin = buyingPowerModel.GetMarginRemaining(algorithm.Portfolio, security, orderDirection); requiredMargin = buyingPowerModel.GetInitialMarginRequiredForOrder(security, order); //Console.WriteLine("Current price: " + security.Price); //Console.WriteLine("Target percentage: " + targetPercentage); //Console.WriteLine("Order direction: " + orderDirection); //Console.WriteLine("Order quantity: " + orderQuantity); //Console.WriteLine("Free margin: " + freeMargin); //Console.WriteLine("Required margin: " + requiredMargin); //Console.WriteLine(); Assert.That(Math.Abs(requiredMargin) <= freeMargin); orderFee = security.FeeModel.GetOrderFee(security, order); fill = new OrderEvent(order, DateTime.UtcNow, orderFee) { FillPrice = security.Price, FillQuantity = orderQuantity }; algorithm.Portfolio.ProcessFill(fill); //Console.WriteLine("Portfolio.Cash: " + algorithm.Portfolio.Cash); //Console.WriteLine("Portfolio.TotalPortfolioValue: " + algorithm.Portfolio.TotalPortfolioValue); //Console.WriteLine(); }
public static async Task ExampleMain(string[] args) { // Initialize REST API client. var api = new BinanceApi(); // Check connectivity. if (await api.PingAsync()) { Console.WriteLine("Successful!"); } // Create user with API-Key and API-Secret. using (var user = new BinanceApiUser("<API-Key>", "<API-Secret>")) { // Create a client (MARKET) order. var order = new MarketOrder(user) { Symbol = Symbol.BTC_USDT, Side = OrderSide.Buy, Quantity = 0.01m }; try { // Send the TEST order. await api.TestPlaceAsync(order); Console.WriteLine("Test Order Successful!"); } catch (Exception e) { Console.WriteLine($"Test Order Failed: \"{e.Message}\""); } } // Initialize web socket client (with automatic streaming enabled). var webSocketClient = new AggregateTradeWebSocketClient(); // Handle error events. webSocketClient.Error += (s, e) => { Console.WriteLine(e.Exception.Message); }; // Subscribe callback to BTC/USDT (automatically begin streaming). webSocketClient.Subscribe(Symbol.BTC_USDT, evt => { var side = evt.Trade.IsBuyerMaker ? "SELL" : "BUY "; // Handle aggregate trade events. Console.WriteLine($"{evt.Trade.Symbol} {side} {evt.Trade.Quantity} @ {evt.Trade.Price}"); }); Console.ReadKey(true); // wait for user input. // Unsubscribe from symbol (automatically end streaming). webSocketClient.Unsubscribe(); // Initiatlize web socket cache (with automatic streaming enabled). var webSocketCache = new DepthWebSocketCache(); // Handle error events. webSocketCache.Error += (s, e) => { Console.WriteLine(e.Exception.Message); }; // Subscribe callback to symbol (automatically begin streaming). webSocketCache.Subscribe(Symbol.BTC_USDT, evt => { // Get symbol from cache (update cache if a symbol is missing). var symbol = Symbol.Cache.Get(evt.OrderBook.Symbol); var minBidPrice = evt.OrderBook.Bids.Last().Price; var maxAskPrice = evt.OrderBook.Asks.Last().Price; // Handle order book update events. Console.WriteLine($"Bid Quantity: {evt.OrderBook.Depth(minBidPrice)} {symbol.BaseAsset} - " + $"Ask Quantity: {evt.OrderBook.Depth(maxAskPrice)} {symbol.BaseAsset}"); }); Console.ReadKey(true); // wait for user input. // Unsubscribe from symbol (automatically end streaming). webSocketCache.Unsubscribe(); }
/// <summary> /// Change parameters for market /// </summary> /// <param name="pos"></param> /// <returns></returns> protected RequestStatus ModifyMarketOrder(MarketOrder pos) { return(robotContext.SendEditMarketRequest(protectedContext.MakeProtectedContext(), pos)); }
/// <summary> /// Вызывается на торговых событиях открытие закрытие позиции, срабатывание тейков и стопов /// </summary> /// <param name="order"></param> public virtual void OnTradeEvent(MarketOrder order) { TerminalLog.Instance.SaveRobotLog(string.Format("робот {0}: срабатывание рыночного ордера {1}, {2}, состояние {3}, side = {4}", TypeName, order.ID, order.Symbol, order.State, order.Side)); }
/// <summary> /// Strategy enter/exit/filtering rules /// </summary> public override void OnNewBar() { decimal stopMargin = (decimal)this.GetInputParameter("Trailing Stop Loss ticks distance") * this.GetMainChart().Symbol.TickSize; int buySignal = (int)this.GetInputParameter("ROCR 100 Buy signal trigger level"); if (rocr100Indicator.GetROCR100()[1] <= buySignal && rocr100Indicator.GetROCR100()[0] > buySignal && this.GetOpenPosition() == 0) { // BUY SIGNAL: Entering long and placing a trailing stop loss MarketOrder buyOrder = new MarketOrder(OrderSide.Buy, 1, "Enter long position"); trailingStopOrder = new StopOrder(OrderSide.Sell, 1, this.Bars.Close[0] - stopMargin, "Trailing stop long exit"); this.InsertOrder(buyOrder); this.InsertOrder(trailingStopOrder); // Resetting acceleration and highest close acceleration = 0.02m; highestClose = Bars.Close[0]; } else if (this.GetOpenPosition() == 1) { // Checking if the price has moved in our favour if (this.Bars.Close[0] > highestClose) { highestClose = this.Bars.Close[0]; // Increasing acceleration acceleration = acceleration * (highestClose - trailingStopOrder.Price); // Checking if trailing the stop order would exceed the current market price if (trailingStopOrder.Price + acceleration < this.Bars.Close[0]) { // Setting the new price for the trailing stop trailingStopOrder.Price = trailingStopOrder.Price + acceleration; this.ModifyOrder(trailingStopOrder); } else { // Cancelling the order and closing the position MarketOrder exitLongOrder = new MarketOrder(OrderSide.Sell, 1, "Exit long position"); this.InsertOrder(exitLongOrder); this.CancelOrder(trailingStopOrder); } } } }
/// <summary> /// Strategy enter/exit/filtering rules /// </summary> public override void OnNewBar() { decimal buySignal = (decimal)this.GetInputParameter("Trend-following buy signal"); decimal sellSignal = (decimal)this.GetInputParameter("Trend-following sell signal"); decimal stopMargin = (int)this.GetInputParameter("Trailing Stop Loss ticks distance") * this.GetMainChart().Symbol.TickSize; decimal profitMargin = (int)this.GetInputParameter("Profit Target ticks distance") * this.GetMainChart().Symbol.TickSize; bool longTradingEnabled = false; bool shortTradingEnabled = false; // Day-of-week filter if (IsDayEnabledForTrading(this.Bars.Time[0].DayOfWeek)) { // Time-of-day filter if (IsTimeEnabledForTrading(this.Bars.Time[0])) { // Volatility filter if (CalculateVolatilityRange() > (decimal)this.GetInputParameter("Minimum Range Filter")) { // ADX minimum level and current trending filters if (this.GetOpenPosition() == 0 && IsADXEnabledForLongEntry() && IsBullishUnderlyingTrend()) { longTradingEnabled = true; } else if (this.GetOpenPosition() == 0 && IsADXEnabledForShortEntry() && IsBearishUnderlyingTrend()) { shortTradingEnabled = true; } } } } if (longTradingEnabled && stochasticIndicator.GetD()[1] <= buySignal && stochasticIndicator.GetD()[0] > buySignal) { // BUY SIGNAL: Stochastic %D crosses above "buy signal" level MarketOrder buyOrder = new MarketOrder(OrderSide.Buy, 1, "Enter long position"); this.InsertOrder(buyOrder); trailingStopOrder = new StopOrder(OrderSide.Sell, 1, this.Bars.Close[0] - stopMargin, "Catastrophic stop long exit"); this.InsertOrder(trailingStopOrder); profitOrder = new LimitOrder(OrderSide.Sell, 1, this.Bars.Close[0] + profitMargin, "Profit stop long exit"); this.InsertOrder(profitOrder); // Linking Stop and Limit orders: when one is executed, the other is cancelled trailingStopOrder.IsChildOf = profitOrder; profitOrder.IsChildOf = trailingStopOrder; // Setting the initial acceleration for the trailing stop and the furthest (the most extreme) close price acceleration = (decimal)this.GetInputParameter("Trailing Stop acceleration"); furthestClose = this.Bars.Close[0]; } else if (shortTradingEnabled && stochasticIndicator.GetD()[1] >= sellSignal && stochasticIndicator.GetD()[0] < sellSignal) { // SELL SIGNAL: Stochastic %D crosses below "sell signal" level MarketOrder sellOrder = new MarketOrder(OrderSide.Sell, 1, "Enter short position"); this.InsertOrder(sellOrder); trailingStopOrder = new StopOrder(OrderSide.Buy, 1, this.Bars.Close[0] + stopMargin, "Catastrophic stop short exit"); this.InsertOrder(trailingStopOrder); profitOrder = new LimitOrder(OrderSide.Buy, 1, this.Bars.Close[0] - profitMargin, "Profit stop short exit"); this.InsertOrder(profitOrder); // Linking Stop and Limit orders: when one is executed, the other is cancelled trailingStopOrder.IsChildOf = profitOrder; profitOrder.IsChildOf = trailingStopOrder; // Setting the initial acceleration for the trailing stop and the furthest (the most extreme) close price acceleration = (decimal)this.GetInputParameter("Trailing Stop acceleration"); furthestClose = this.Bars.Close[0]; } else if (this.GetOpenPosition() == 1 && this.Bars.Close[0] > furthestClose) { // We're long and the price has moved in our favour furthestClose = this.Bars.Close[0]; // Increasing acceleration acceleration = acceleration * (furthestClose - trailingStopOrder.Price); // Checking if trailing the stop order would exceed the current market price if (trailingStopOrder.Price + acceleration < this.Bars.Close[0]) { // Setting the new price for the trailing stop trailingStopOrder.Price = trailingStopOrder.Price + acceleration; trailingStopOrder.Label = "Trailing stop long exit"; this.ModifyOrder(trailingStopOrder); } else { // Cancelling the order and closing the position this.CancelOrder(trailingStopOrder); this.CancelOrder(profitOrder); MarketOrder exitLongOrder = new MarketOrder(OrderSide.Sell, 1, "Exit long position"); this.InsertOrder(exitLongOrder); } } else if (this.GetOpenPosition() == -1 && this.Bars.Close[0] < furthestClose) { // We're short and the price has moved in our favour furthestClose = this.Bars.Close[0]; // Increasing acceleration acceleration = acceleration * Math.Abs(trailingStopOrder.Price - furthestClose); // Checking if trailing the stop order would exceed the current market price if (trailingStopOrder.Price - acceleration > this.Bars.Close[0]) { // Setting the new price for the trailing stop trailingStopOrder.Price = trailingStopOrder.Price - acceleration; trailingStopOrder.Label = "Trailing stop short exit"; this.ModifyOrder(trailingStopOrder); } else { // Cancelling the order and closing the position this.CancelOrder(trailingStopOrder); this.CancelOrder(profitOrder); MarketOrder exitShortOrder = new MarketOrder(OrderSide.Buy, 1, "Exit short position"); this.InsertOrder(exitShortOrder); } } }
public void ComputeMarginProperlyAsSecurityPriceFluctuates() { const decimal leverage = 1m; const int quantity = (int)(1000 * leverage); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var orderProcessor = new OrderProcessor(); transactions.SetOrderProcessor(orderProcessor); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].SetAmount(quantity); var config = CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL); securities.Add(new Security(SecurityExchangeHours, config)); var security = securities[Symbols.AAPL]; security.SetLeverage(leverage); var time = DateTime.Now; const decimal buyPrice = 1m; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, buyPrice, buyPrice, buyPrice, buyPrice, 1)); var order = new MarketOrder(Symbols.AAPL, quantity, time) { Price = buyPrice }; var fill = new OrderEvent(order, DateTime.UtcNow, 0) { FillPrice = buyPrice, FillQuantity = quantity }; orderProcessor.AddOrder(order); var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, order.Time, null); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(null, request)); Assert.AreEqual(portfolio.CashBook["USD"].Amount, fill.FillPrice * fill.FillQuantity); portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var newOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1)) { Price = buyPrice }; bool sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsFalse(sufficientCapital); // now the stock doubles, so we should have margin remaining time = time.AddDays(1); const decimal highPrice = buyPrice * 2; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, highPrice, highPrice, highPrice, highPrice, 1)); Assert.AreEqual(quantity, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity * 2, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var anotherOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1)) { Price = highPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, anotherOrder); Assert.IsTrue(sufficientCapital); // now the stock plummets, so we should have negative margin remaining time = time.AddDays(1); const decimal lowPrice = buyPrice / 2; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, lowPrice, lowPrice, lowPrice, lowPrice, 1)); Assert.AreEqual(-quantity / 2m, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity / 2m, portfolio.TotalPortfolioValue); // this would not cause a margin call due to leverage = 1 bool issueMarginCallWarning; var marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning); Assert.AreEqual(0, marginCallOrders.Count); // now change the leverage and buy more and we'll get a margin call security.SetLeverage(leverage * 2); order = new MarketOrder(Symbols.AAPL, quantity, time) { Price = buyPrice }; fill = new OrderEvent(order, DateTime.UtcNow, 0) { FillPrice = buyPrice, FillQuantity = quantity }; portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.TotalPortfolioValue); marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning); Assert.AreNotEqual(0, marginCallOrders.Count); Assert.AreEqual(-security.Holdings.Quantity, marginCallOrders[0].Quantity); // we bought twice Assert.GreaterOrEqual(-portfolio.MarginRemaining, security.Price * marginCallOrders[0].Quantity); }
/// <summary> /// Default market fill model for the base security class. Fills at the last traded price. /// </summary> /// <param name="asset">Security asset we're filling</param> /// <param name="order">Order packet to model</param> /// <returns>Order fill information detailing the average price and quantity filled.</returns> /// <seealso cref="StopMarketFill(Security, StopMarketOrder)"/> /// <seealso cref="LimitFill(Security, LimitOrder)"/> public virtual OrderEvent MarketFill(Security asset, MarketOrder order) { return(_fillModel.MarketFill(asset, order)); }
public void MarginComputesProperlyWithMultipleSecurities() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var orderProcessor = new OrderProcessor(); transactions.SetOrderProcessor(orderProcessor); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].SetAmount(1000); portfolio.CashBook.Add("EUR", 1000, 1.1m); portfolio.CashBook.Add("GBP", -1000, 2.0m); var eurCash = portfolio.CashBook["EUR"]; var gbpCash = portfolio.CashBook["GBP"]; var usdCash = portfolio.CashBook["USD"]; var time = DateTime.Now; var config1 = CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL); securities.Add(new Security(SecurityExchangeHours, config1)); securities[Symbols.AAPL].SetLeverage(2m); securities[Symbols.AAPL].Holdings.SetHoldings(100, 100); securities[Symbols.AAPL].SetMarketPrice(new TradeBar { Time = time, Value = 100 }); //Console.WriteLine("AAPL TMU: " + securities[Symbols.AAPL].MarginModel.GetMaintenanceMargin(securities[Symbols.AAPL])); //Console.WriteLine("AAPL Value: " + securities[Symbols.AAPL].Holdings.HoldingsValue); //Console.WriteLine(); var config2 = CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURUSD); securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, usdCash, config2)); securities[Symbols.EURUSD].SetLeverage(100m); securities[Symbols.EURUSD].Holdings.SetHoldings(1.1m, 1000); securities[Symbols.EURUSD].SetMarketPrice(new TradeBar { Time = time, Value = 1.1m }); //Console.WriteLine("EURUSD TMU: " + securities[Symbols.EURUSD].MarginModel.GetMaintenanceMargin(securities[Symbols.EURUSD])); //Console.WriteLine("EURUSD Value: " + securities[Symbols.EURUSD].Holdings.HoldingsValue); //Console.WriteLine(); var config3 = CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURGBP); securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, gbpCash, config3)); securities[Symbols.EURGBP].SetLeverage(100m); securities[Symbols.EURGBP].Holdings.SetHoldings(1m, 1000); securities[Symbols.EURGBP].SetMarketPrice(new TradeBar { Time = time, Value = 1m }); //Console.WriteLine("EURGBP TMU: " + securities[Symbols.EURGBP].MarginModel.GetMaintenanceMargin(securities[Symbols.EURGBP])); //Console.WriteLine("EURGBP Value: " + securities[Symbols.EURGBP].Holdings.HoldingsValue); //Console.WriteLine(); //Console.WriteLine(portfolio.CashBook["USD"]); //Console.WriteLine(portfolio.CashBook["EUR"]); //Console.WriteLine(portfolio.CashBook["GBP"]); //Console.WriteLine("CashBook: " + portfolio.CashBook.TotalValueInAccountCurrency); //Console.WriteLine(); //Console.WriteLine("Total Margin Used: " + portfolio.TotalMarginUsed); //Console.WriteLine("Total Free Margin: " + portfolio.MarginRemaining); //Console.WriteLine("Total Portfolio Value: " + portfolio.TotalPortfolioValue); var acceptedOrder = new MarketOrder(Symbols.AAPL, 101, DateTime.Now) { Price = 100 }; orderProcessor.AddOrder(acceptedOrder); var request = new SubmitOrderRequest(OrderType.Market, acceptedOrder.SecurityType, acceptedOrder.Symbol, acceptedOrder.Quantity, 0, 0, acceptedOrder.Time, null); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(null, request)); var sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, acceptedOrder); Assert.IsTrue(sufficientCapital); var rejectedOrder = new MarketOrder(Symbols.AAPL, 102, DateTime.Now) { Price = 100 }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, rejectedOrder); Assert.IsFalse(sufficientCapital); }
/// <summary> /// Calculate the order quantity to achieve target-percent holdings. /// </summary> /// <param name="symbol">Security object we're asking for</param> /// <param name="target">Target percentag holdings, this is an unlevered value, so /// if you have 2x leverage and request 100% holdings, it will utilize half of the /// available margin</param> /// <returns>Order quantity to achieve this percentage</returns> public decimal CalculateOrderQuantity(Symbol symbol, decimal target) { var security = Securities[symbol]; var price = security.Price; // can't order it if we don't have data if (price == 0) { return(0); } // if targeting zero, simply return the negative of the quantity if (target == 0) { return(-security.Holdings.Quantity); } // this is the value in dollars that we want our holdings to have var targetPortfolioValue = target * Portfolio.TotalPortfolioValue; var currentHoldingsValue = security.Holdings.HoldingsValue; // remove directionality, we'll work in the land of absolutes var targetOrderValue = Math.Abs(targetPortfolioValue - currentHoldingsValue); var direction = targetPortfolioValue > currentHoldingsValue ? OrderDirection.Buy : OrderDirection.Sell; // determine the unit price in terms of the account currency var unitPrice = new MarketOrder(symbol, 1, UtcTime).GetValue(security); if (unitPrice == 0) { return(0); } // calculate the total margin available var marginRemaining = Portfolio.GetMarginRemaining(symbol, direction); if (marginRemaining <= 0) { return(0); } // continue iterating while we do not have enough margin for the order decimal marginRequired; decimal orderValue; decimal orderFees; var feeToPriceRatio = 0; // compute the initial order quantity decimal orderQuantity = targetOrderValue / unitPrice; if (orderQuantity % security.SymbolProperties.LotSize != 0) { orderQuantity = orderQuantity - (orderQuantity % security.SymbolProperties.LotSize); } var iterations = 0; do { // decrease the order quantity if (iterations > 0) { // if fees are high relative to price, we reduce the order quantity faster if (feeToPriceRatio > 0) { orderQuantity -= feeToPriceRatio; } else { orderQuantity--; } } // generate the order var order = new MarketOrder(security.Symbol, orderQuantity, UtcTime); orderValue = order.GetValue(security); orderFees = security.FeeModel.GetOrderFee(security, order); feeToPriceRatio = (int)(orderFees / unitPrice); // calculate the margin required for the order marginRequired = security.MarginModel.GetInitialMarginRequiredForOrder(security, order); iterations++; } while (orderQuantity > 0 && (marginRequired > marginRemaining || orderValue + orderFees > targetOrderValue)); //Rounding off Order Quantity to the nearest multiple of Lot Size if (orderQuantity % security.SymbolProperties.LotSize != 0) { orderQuantity = orderQuantity - (orderQuantity % security.SymbolProperties.LotSize); } // add directionality back in return((direction == OrderDirection.Sell ? -1 : 1) * orderQuantity); }
private static DateTime InitializeTest(out BasicTemplateAlgorithm algorithm, out Security security, out PartialMarketFillModel model, out MarketOrder order, out OrderTicket ticket) { var referenceTimeNY = new DateTime(2015, 12, 21, 13, 0, 0); var referenceTimeUtc = referenceTimeNY.ConvertToUtc(TimeZones.NewYork); algorithm = new BasicTemplateAlgorithm(); algorithm.SetDateTime(referenceTimeUtc); var transactionHandler = new BacktestingTransactionHandler(); transactionHandler.Initialize(algorithm, new BacktestingBrokerage(algorithm), new TestResultHandler(Console.WriteLine)); Task.Run(() => transactionHandler.Run()); algorithm.Transactions.SetOrderProcessor(transactionHandler); var config = new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Second, TimeZones.NewYork, TimeZones.NewYork, false, false, false); security = new Security(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), config, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); model = new PartialMarketFillModel(algorithm.Transactions, 2); algorithm.Securities.Add(security); algorithm.Securities[Symbols.SPY].FillModel = model; security.SetMarketPrice(new Tick { Symbol = Symbols.SPY, Value = 100 }); algorithm.SetFinishedWarmingUp(); order = new MarketOrder(Symbols.SPY, 100, referenceTimeUtc) { Id = 1 }; var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, algorithm.UtcTime, null); ticket = algorithm.Transactions.ProcessRequest(request); return(referenceTimeUtc); }
public override OrderEvent MarketFill(Security asset, MarketOrder order) { MarketFillWasCalled = true; return(base.MarketFill(asset, order)); }
public void ComputeMarginProperlyAsSecurityPriceFluctuates() { const int quantity = 1000; var securities = new SecurityManager(); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].Quantity = quantity; var config = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Equity, "AAPL", Resolution.Minute, true, true, true, true, true, 0); securities.Add(new Security(config, 1, false)); var time = DateTime.Now; const decimal buyPrice = 1m; securities["AAPL"].SetMarketPrice(time, new TradeBar(time, "AAPL", buyPrice, buyPrice, buyPrice, buyPrice, 1)); var order = new MarketOrder("AAPL", quantity, time) { Price = buyPrice }; var fill = new OrderEvent(order) { FillPrice = buyPrice, FillQuantity = quantity }; Assert.AreEqual(portfolio.CashBook["USD"].Quantity, fill.FillPrice * fill.FillQuantity); portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var newOrder = new MarketOrder("AAPL", 1, time.AddSeconds(1)) { Price = buyPrice }; bool sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsFalse(sufficientCapital); // now the stock doubles, so we should have margin remaining time = time.AddDays(1); const decimal highPrice = buyPrice * 2; securities["AAPL"].SetMarketPrice(time, new TradeBar(time, "AAPL", highPrice, highPrice, highPrice, highPrice, 1)); Assert.AreEqual(quantity, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity * 2, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var anotherOrder = new MarketOrder("AAPL", 1, time.AddSeconds(1)) { Price = highPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, anotherOrder); Assert.IsTrue(sufficientCapital); // now the stock plummets, so we should have negative margin remaining time = time.AddDays(1); const decimal lowPrice = buyPrice / 2; securities["AAPL"].SetMarketPrice(time, new TradeBar(time, "AAPL", lowPrice, lowPrice, lowPrice, lowPrice, 1)); Assert.AreEqual(-quantity / 2m, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity / 2m, portfolio.TotalPortfolioValue); // this would cause a margin call var marginCallOrders = portfolio.ScanForMarginCall(); Assert.AreNotEqual(0, marginCallOrders.Count); Assert.AreEqual(-quantity, marginCallOrders[0].Quantity); Assert.GreaterOrEqual(-portfolio.MarginRemaining, marginCallOrders[0].Price * marginCallOrders[0].Quantity); }
public PyDataType ModifyCharOrder(PyInteger orderID, PyDecimal newPrice, PyInteger bid, PyInteger stationID, PyInteger solarSystemID, PyDecimal price, PyInteger volRemaining, PyInteger issued, CallInformation call) { int callerCharacterID = call.Client.EnsureCharacterIsSelected(); Character character = this.ItemFactory.GetItem <Character>(callerCharacterID); using MySqlConnection connection = this.DB.AcquireMarketLock(); try { MarketOrder order = this.DB.GetOrderById(connection, orderID); if (order.CharacterID != callerCharacterID) { throw new MktOrderDidNotMatch(); } long currentTime = DateTime.UtcNow.ToFileTimeUtc(); // check for timers, no changes in less than 5 minutes if (currentTime < order.Issued + TimeSpan.TicksPerSecond * this.NodeContainer.Constants[Constants.mktModificationDelay]) { throw new MktOrderDelay((order.Issued + TimeSpan.TicksPerSecond * this.NodeContainer.Constants[Constants.mktModificationDelay]) - currentTime); } // ensure the order hasn't been modified since the user saw it on the screen if ((int)order.Bid != bid || order.LocationID != stationID || order.Price != price || order.UnitsLeft != volRemaining || order.Issued != issued) { throw new MktOrderDidNotMatch(); } // get the modification broker's fee double brokerCost = 0.0; double newEscrow = 0.0; this.CalculateBrokerCost(character.GetSkillLevel(Types.BrokerRelations), volRemaining, (newPrice - price), out brokerCost); using Wallet wallet = this.WalletManager.AcquireWallet(order.CharacterID, order.AccountID); { if (order.Bid == TransactionType.Buy) { // calculate the difference in escrow newEscrow = volRemaining * newPrice; double escrowDiff = order.Escrow - newEscrow; // ensure enough balances wallet.EnsureEnoughBalance(escrowDiff + brokerCost); // take the difference in escrow wallet.CreateJournalRecord(MarketReference.MarketEscrow, null, null, escrowDiff); } else { wallet.EnsureEnoughBalance(brokerCost); } // pay the broker fee once again wallet.CreateJournalRecord(MarketReference.Brokerfee, null, null, -brokerCost); } // everything looks okay, update the price of the order this.DB.UpdatePrice(connection, order.OrderID, newPrice, newEscrow); // send a OnOwnOrderChange notification call.Client.NotifyMultiEvent(new OnOwnOrderChanged(order.TypeID, "Modified")); } finally { this.DB.ReleaseMarketLock(connection); } return(null); }
public void MarginComputesProperlyWithMultipleSecurities() { var securities = new SecurityManager(); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].Quantity = 1000; portfolio.CashBook.Add("EUR", 1000, 1.1m); portfolio.CashBook.Add("GBP", -1000, 2.0m); var eurCash = portfolio.CashBook["EUR"]; var gbpCash = portfolio.CashBook["GBP"]; var usdCash = portfolio.CashBook["USD"]; var time = DateTime.Now; var config1 = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Equity, "AAPL", Resolution.Minute, true, true, true, true, true, 0); securities.Add(new Security(config1, 2, false)); securities["AAPL"].Holdings.SetHoldings(100, 100); securities["AAPL"].SetMarketPrice(time, new TradeBar { Time = time, Value = 100 }); //Console.WriteLine("AAPL TMU: " + securities["AAPL"].MarginModel.GetMaintenanceMargin(securities["AAPL"])); //Console.WriteLine("AAPL Value: " + securities["AAPL"].Holdings.HoldingsValue); //Console.WriteLine(); var config2 = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Forex, "EURUSD", Resolution.Minute, true, true, true, true, true, 1); securities.Add(new QuantConnect.Securities.Forex.Forex(usdCash, config2, 100, false)); securities["EURUSD"].Holdings.SetHoldings(1.1m, 1000); securities["EURUSD"].SetMarketPrice(time, new TradeBar { Time = time, Value = 1.1m }); //Console.WriteLine("EURUSD TMU: " + securities["EURUSD"].MarginModel.GetMaintenanceMargin(securities["EURUSD"])); //Console.WriteLine("EURUSD Value: " + securities["EURUSD"].Holdings.HoldingsValue); //Console.WriteLine(); var config3 = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Forex, "EURGBP", Resolution.Minute, true, true, true, true, true, 2); securities.Add(new QuantConnect.Securities.Forex.Forex(gbpCash, config3, 100, false)); securities["EURGBP"].Holdings.SetHoldings(1m, 1000); securities["EURGBP"].SetMarketPrice(time, new TradeBar { Time = time, Value = 1m }); //Console.WriteLine("EURGBP TMU: " + securities["EURGBP"].MarginModel.GetMaintenanceMargin(securities["EURGBP"])); //Console.WriteLine("EURGBP Value: " + securities["EURGBP"].Holdings.HoldingsValue); //Console.WriteLine(); //Console.WriteLine(portfolio.CashBook["USD"]); //Console.WriteLine(portfolio.CashBook["EUR"]); //Console.WriteLine(portfolio.CashBook["GBP"]); //Console.WriteLine("CashBook: " + portfolio.CashBook.TotalValueInAccountCurrency); //Console.WriteLine(); //Console.WriteLine("Total Margin Used: " + portfolio.TotalMarginUsed); //Console.WriteLine("Total Free Margin: " + portfolio.MarginRemaining); //Console.WriteLine("Total Portfolio Value: " + portfolio.TotalPortfolioValue); var acceptedOrder = new MarketOrder("AAPL", 101, DateTime.Now) { Price = 100 }; var sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, acceptedOrder); Assert.IsTrue(sufficientCapital); var rejectedOrder = new MarketOrder("AAPL", 102, DateTime.Now) { Price = 100 }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, rejectedOrder); Assert.IsFalse(sufficientCapital); }
/// <summary> /// Get the maximum market order quantity to obtain a position with a given value in account currency. /// Will not take into account buying power. /// </summary> /// <param name="parameters">An object containing the portfolio, the security and the target percentage holdings</param> /// <returns>Returns the maximum allowed market order quantity and if zero, also the reason</returns> public virtual GetMaximumOrderQuantityForTargetValueResult GetMaximumOrderQuantityForTargetValue(GetMaximumOrderQuantityForTargetValueParameters parameters) { // adjust target portfolio value to comply with required Free Buying Power Percent var targetPortfolioValue = parameters.Target * (parameters.Portfolio.TotalPortfolioValue - parameters.Portfolio.TotalPortfolioValue * RequiredFreeBuyingPowerPercent); // if targeting zero, simply return the negative of the quantity if (targetPortfolioValue == 0) { return(new GetMaximumOrderQuantityForTargetValueResult(-parameters.Security.Holdings.Quantity, string.Empty, false)); } var currentHoldingsValue = parameters.Security.Holdings.HoldingsValue; // remove directionality, we'll work in the land of absolutes var targetOrderValue = Math.Abs(targetPortfolioValue - currentHoldingsValue); var direction = targetPortfolioValue > currentHoldingsValue ? OrderDirection.Buy : OrderDirection.Sell; // determine the unit price in terms of the account currency var unitPrice = new MarketOrder(parameters.Security.Symbol, 1, DateTime.UtcNow).GetValue(parameters.Security); if (unitPrice == 0) { var reason = $"The price of the {parameters.Security.Symbol.Value} security is zero because it does not have any market " + "data yet. When the security price is set this security will be ready for trading."; return(new GetMaximumOrderQuantityForTargetValueResult(0, reason)); } // calculate the total margin available var marginRemaining = GetMarginRemaining(parameters.Portfolio, parameters.Security, direction); if (marginRemaining <= 0) { var reason = "The portfolio does not have enough margin available."; return(new GetMaximumOrderQuantityForTargetValueResult(0, reason)); } // continue iterating while we do not have enough margin for the order decimal orderValue = 0; decimal orderFees = 0; // compute the initial order quantity var orderQuantity = targetOrderValue / unitPrice; // rounding off Order Quantity to the nearest multiple of Lot Size orderQuantity -= orderQuantity % parameters.Security.SymbolProperties.LotSize; if (orderQuantity == 0) { var reason = $"The order quantity is less than the lot size of {parameters.Security.SymbolProperties.LotSize} " + "and has been rounded to zero."; return(new GetMaximumOrderQuantityForTargetValueResult(0, reason, false)); } var loopCount = 0; // Just in case... var lastOrderQuantity = 0m; do { // Each loop will reduce the order quantity based on the difference between orderValue and targetOrderValue if (orderValue > targetOrderValue) { var currentOrderValuePerUnit = orderValue / orderQuantity; var amountOfOrdersToRemove = (orderValue - targetOrderValue) / currentOrderValuePerUnit; if (amountOfOrdersToRemove < parameters.Security.SymbolProperties.LotSize) { // we will always substract at leat 1 LotSize amountOfOrdersToRemove = parameters.Security.SymbolProperties.LotSize; } orderQuantity -= amountOfOrdersToRemove; orderQuantity -= orderQuantity % parameters.Security.SymbolProperties.LotSize; } if (orderQuantity <= 0) { var reason = $"The order quantity is less than the lot size of {parameters.Security.SymbolProperties.LotSize} " + $"and has been rounded to zero.Target order value {targetOrderValue}. Order fees " + $"{orderFees}. Order quantity {orderQuantity}."; return(new GetMaximumOrderQuantityForTargetValueResult(0, reason)); } // generate the order var order = new MarketOrder(parameters.Security.Symbol, orderQuantity, DateTime.UtcNow); var fees = parameters.Security.FeeModel.GetOrderFee( new OrderFeeParameters(parameters.Security, order, parameters.Portfolio.CashBook.AccountCurrency)).Value; orderFees = parameters.Portfolio.CashBook.ConvertToAccountCurrency(fees).Amount; // The TPV, take out the fees(unscaled) => yields available value for trading(less fees) // then scale that by the target -- finally remove currentHoldingsValue to get targetOrderValue targetOrderValue = Math.Abs( (parameters.Portfolio.TotalPortfolioValue - orderFees - parameters.Portfolio.TotalPortfolioValue * RequiredFreeBuyingPowerPercent) * parameters.Target - currentHoldingsValue ); // After the first loop we need to recalculate order quantity since now we have fees included if (loopCount == 0) { // re compute the initial order quantity orderQuantity = targetOrderValue / unitPrice; orderQuantity -= orderQuantity % parameters.Security.SymbolProperties.LotSize; } else { // Start safe check after first loop if (lastOrderQuantity == orderQuantity) { var message = "GetMaximumOrderQuantityForTargetValue failed to converge to target order value " + $"{targetOrderValue}. Current order value is {orderValue}. Order quantity {orderQuantity}. " + $"Lot size is {parameters.Security.SymbolProperties.LotSize}. Order fees {orderFees}. Security symbol " + $"{parameters.Security.Symbol}"; throw new Exception(message); } lastOrderQuantity = orderQuantity; } orderValue = orderQuantity * unitPrice; loopCount++; // we always have to loop at least twice }while (loopCount < 2 || orderValue > targetOrderValue); // add directionality back in return(new GetMaximumOrderQuantityForTargetValueResult((direction == OrderDirection.Sell ? -1 : 1) * orderQuantity)); }
/// <summary> /// Strategy enter/exit/filtering rules /// </summary> public override void OnNewBar() { if (this.GetOpenPosition() == 0) { int buySignal = (int)this.GetInputParameter("Stochastic %D Buy signal trigger level"); if (stochasticIndicator.GetD()[1] <= buySignal && stochasticIndicator.GetD()[0] > buySignal) { Order buyOrder = new MarketOrder(OrderSide.Buy, 1, "Entry long"); limitTakeProfitOrder = new LimitOrder(OrderSide.Sell, 1, Bars.Close[0] + stdDevIndicator.GetStdDev()[0], "Exit long (take profit stop)"); this.InsertOrder(buyOrder); this.InsertOrder(limitTakeProfitOrder); } } }
/// <summary> /// Gets all orders not yet closed /// </summary> /// <returns></returns> public override List <Order> GetOpenOrders() { var list = new List <Order>(); var req = new RestRequest("/orders?status=open&status=pending&status=active", Method.GET); GetAuthenticationToken(req); var response = ExecuteRestRequest(req, GdaxEndpointType.Private); if (response.StatusCode != HttpStatusCode.OK) { throw new Exception($"GDAXBrokerage.GetOpenOrders: request failed: [{(int) response.StatusCode}] {response.StatusDescription}, Content: {response.Content}, ErrorMessage: {response.ErrorMessage}"); } var orders = JsonConvert.DeserializeObject <Messages.Order[]>(response.Content); foreach (var item in orders) { Order order; if (item.Type == "market") { order = new MarketOrder { Price = item.Price }; } else if (!string.IsNullOrEmpty(item.Stop)) { order = new StopLimitOrder { StopPrice = item.StopPrice, LimitPrice = item.Price }; } else if (item.Type == "limit") { order = new LimitOrder { LimitPrice = item.Price }; } else if (item.Type == "stop") { order = new StopMarketOrder { StopPrice = item.Price }; } else { OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Error, (int)response.StatusCode, "GDAXBrokerage.GetOpenOrders: Unsupported order type returned from brokerage: " + item.Type)); continue; } order.Quantity = item.Side == "sell" ? -item.Size : item.Size; order.BrokerId = new List <string> { item.Id }; order.Symbol = ConvertProductId(item.ProductId); order.Time = DateTime.UtcNow; order.Status = ConvertOrderStatus(item); order.Price = item.Price; list.Add(order); } foreach (var item in list) { if (item.Status.IsOpen()) { var cached = CachedOrderIDs.Where(c => c.Value.BrokerId.Contains(item.BrokerId.First())); if (cached.Any()) { CachedOrderIDs[cached.First().Key] = item; } } } return(list); }
/// <summary> /// Get the maximum market order quantity to obtain a position with a given buying power percentage. /// Will not take into account free buying power. /// </summary> /// <param name="parameters">An object containing the portfolio, the security and the target signed buying power percentage</param> /// <returns>Returns the maximum allowed market order quantity and if zero, also the reason</returns> public override GetMaximumOrderQuantityResult GetMaximumOrderQuantityForTargetBuyingPower(GetMaximumOrderQuantityForTargetBuyingPowerParameters parameters) { var targetPortfolioValue = parameters.TargetBuyingPower * parameters.Portfolio.TotalPortfolioValue; // no shorting allowed if (targetPortfolioValue < 0) { return(new GetMaximumOrderQuantityResult(0, "The cash model does not allow shorting.")); } var baseCurrency = parameters.Security as IBaseCurrencySymbol; if (baseCurrency == null) { return(new GetMaximumOrderQuantityResult(0, "The security type must be SecurityType.Crypto or SecurityType.Forex.")); } // if target value is zero, return amount of base currency available to sell if (targetPortfolioValue == 0) { return(new GetMaximumOrderQuantityResult(-parameters.Portfolio.CashBook[baseCurrency.BaseCurrencySymbol].Amount)); } // convert base currency cash to account currency var baseCurrencyPosition = parameters.Portfolio.CashBook.ConvertToAccountCurrency( parameters.Portfolio.CashBook[baseCurrency.BaseCurrencySymbol].Amount, baseCurrency.BaseCurrencySymbol); // remove directionality, we'll work in the land of absolutes var targetOrderValue = Math.Abs(targetPortfolioValue - baseCurrencyPosition); var direction = targetPortfolioValue > baseCurrencyPosition ? OrderDirection.Buy : OrderDirection.Sell; // determine the unit price in terms of the account currency var unitPrice = direction == OrderDirection.Buy ? parameters.Security.AskPrice : parameters.Security.BidPrice; unitPrice *= parameters.Security.QuoteCurrency.ConversionRate * parameters.Security.SymbolProperties.ContractMultiplier; if (unitPrice == 0) { if (parameters.Security.QuoteCurrency.ConversionRate == 0) { return(new GetMaximumOrderQuantityResult(0, "The internal cash feed required for converting" + Invariant($" {parameters.Security.QuoteCurrency.Symbol} to {parameters.Portfolio.CashBook.AccountCurrency} does not") + " have any data yet (or market may be closed).")); } if (parameters.Security.SymbolProperties.ContractMultiplier == 0) { return(new GetMaximumOrderQuantityResult(0, $"The contract multiplier for the {parameters.Security.Symbol.Value} security is zero. The symbol properties database may be out of date.")); } // security.Price == 0 return(new GetMaximumOrderQuantityResult(0, parameters.Security.Symbol.GetZeroPriceMessage())); } // continue iterating while we do not have enough cash for the order decimal orderFees = 0; decimal currentOrderValue = 0; // compute the initial order quantity var orderQuantity = targetOrderValue / unitPrice; // rounding off Order Quantity to the nearest multiple of Lot Size orderQuantity -= orderQuantity % parameters.Security.SymbolProperties.LotSize; if (orderQuantity == 0) { string reason = null; if (!parameters.SilenceNonErrorReasons) { reason = Invariant( $"The order quantity is less than the lot size of {parameters.Security.SymbolProperties.LotSize} and has been rounded to zero." ); } return(new GetMaximumOrderQuantityResult(0, reason, false)); } // Just in case... var lastOrderQuantity = 0m; var utcTime = parameters.Security.LocalTime.ConvertToUtc(parameters.Security.Exchange.TimeZone); do { // Each loop will reduce the order quantity based on the difference between // (cashRequired + orderFees) and targetOrderValue if (currentOrderValue > targetOrderValue) { var currentOrderValuePerUnit = currentOrderValue / orderQuantity; var amountOfOrdersToRemove = (currentOrderValue - targetOrderValue) / currentOrderValuePerUnit; if (amountOfOrdersToRemove < parameters.Security.SymbolProperties.LotSize) { // we will always substract at leat 1 LotSize amountOfOrdersToRemove = parameters.Security.SymbolProperties.LotSize; } orderQuantity -= amountOfOrdersToRemove; } // rounding off Order Quantity to the nearest multiple of Lot Size orderQuantity -= orderQuantity % parameters.Security.SymbolProperties.LotSize; if (orderQuantity <= 0) { return(new GetMaximumOrderQuantityResult(0, Invariant($"The order quantity is less than the lot size of {parameters.Security.SymbolProperties.LotSize} and has been rounded to zero.") + Invariant($"Target order value {targetOrderValue}. Order fees {orderFees}. Order quantity {orderQuantity}.") )); } if (lastOrderQuantity == orderQuantity) { throw new ArgumentException( Invariant($"GetMaximumOrderQuantityForTargetValue failed to converge to target order value {targetOrderValue}. ") + Invariant($"Current order value is {currentOrderValue}. Order quantity {orderQuantity}. Lot size is ") + Invariant($"{parameters.Security.SymbolProperties.LotSize}. Order fees {orderFees}. Security symbol {parameters.Security.Symbol}") ); } lastOrderQuantity = orderQuantity; // generate the order var order = new MarketOrder(parameters.Security.Symbol, orderQuantity, utcTime); var orderValue = orderQuantity * unitPrice; var fees = parameters.Security.FeeModel.GetOrderFee( new OrderFeeParameters(parameters.Security, order)).Value; orderFees = parameters.Portfolio.CashBook.ConvertToAccountCurrency(fees).Amount; currentOrderValue = orderValue + orderFees; } while (currentOrderValue > targetOrderValue); // add directionality back in return(new GetMaximumOrderQuantityResult((direction == OrderDirection.Sell ? -1 : 1) * orderQuantity)); }
private void RenderAccountPositions(StringBuilder sb, int accountId) { List <MarketOrder> orders; var accountInfo = GetAccountInfoFromServer(accountId, out orders); if (accountInfo == null) { return; } var tradeSignalRequestScript = RenderAjaxSignalDetailQuery(sb); // краткая сводка по счету sb.AppendLine(" <h3>Счет " + accountId + "</h3>"); sb.AppendLine(" <p>"); var ptrVal = new Dictionary <string, string> { { "Баланс", accountInfo.Equity.ToStringUniformMoneyFormat() + " " + accountInfo.Currency }, { "Текущая прибыль/убыток", (accountInfo.Equity - accountInfo.Balance).ToStringUniformMoneyFormat() + " " + accountInfo.Currency }, { "Группа", accountInfo.Group } }; foreach (var pair in ptrVal) { sb.AppendLine(" " + pair.Key + ": " + pair.Value + "<br/>"); } sb.AppendLine(" </p>"); // рендерить таблицу открытых позиций RenderTableOpenTag(sb); RenderTableRowTag(sb, true); sb.AppendLine(" <td>№</td><td>Тип</td><td>Объем</td><td>Инстр.</td>" + "<td>Цена</td><td>Время</td><td>Выход</td><td>Результат</td><td>SL</td><td>TP</td><td>Сиг.</td></tr>"); var evenRow = false; var colorSchemeText = new Dictionary <Cortege2 <bool, bool>, string> { { new Cortege2 <bool, bool>(true, true), "Black" }, // even - profit { new Cortege2 <bool, bool>(false, true), "Black" }, // odd - profit { new Cortege2 <bool, bool>(false, false), "Black" }, // odd - loss { new Cortege2 <bool, bool>(true, false), "#860000" } // even - loss }; var colorSchemeBack = new Dictionary <Cortege2 <bool, bool>, string> { { new Cortege2 <bool, bool>(true, true), "White" }, // even - profit { new Cortege2 <bool, bool>(false, true), "#E0E0E0" }, // odd - profit { new Cortege2 <bool, bool>(false, false), "FFD6D6" }, // odd - loss { new Cortege2 <bool, bool>(true, false), "#White" } // even - loss }; foreach (var order in orders) { evenRow = !evenRow; var colorText = colorSchemeText[new Cortege2 <bool, bool>(evenRow, order.ResultDepo >= 0)]; var colorBack = colorSchemeBack[new Cortege2 <bool, bool>(evenRow, order.ResultDepo >= 0)]; sb.AppendLine(string.Format(" <tr style=\"color:{0}; background-color:{1}\">", colorText, colorBack)); int signalCat, parentDeal; var signalString = ""; if (MarketOrder.GetTradeSignalFromDeal(order, out signalCat, out parentDeal)) { signalString = string.Format("<a href=\"#\" onclick=\"{0}({1})\">[{1}]</a>", tradeSignalRequestScript, signalCat); } sb.AppendLine(string.Format(" <td>{0}</td><td>{1}</td><td>{2}</td>" + "<td>{3}</td><td>{4}</td><td>{5:dd.MM.yyyy HH:mm:ss}</td><td>{6}</td><td>{7}</td><td>{8}</td><td>{9}</td><td>{10}</td></tr>", order.ID, order.Side > 0 ? "BUY" : "SELL", order.Volume.ToStringUniformMoneyFormat(), order.Symbol, order.PriceEnter.ToStringUniformMoneyFormat(), order.TimeEnter, (order.PriceExit ?? 0).ToStringUniformPriceFormat(), order.ResultDepo.ToStringUniformMoneyFormat(), order.StopLoss.HasValue ? order.StopLoss.Value.ToStringUniformPriceFormat() : " ", order.TakeProfit.HasValue ? order.TakeProfit.Value.ToStringUniformPriceFormat() : " ", signalString)); } }
private void MarketDataRoutine(object obj) { int index = (int)obj; while (true) { if (_isRunning == true && _source != null) { if (_source.MarketDataCache.Count > 0) { TDFMarketData[] tmd; if (_source.MarketDataCache.TryDequeue(out tmd)) { MarketData[] md = new MarketData[tmd.Length]; for (int i = 0; i < tmd.Length; i++) { md[i] = new MarketData(); md[i].WindCode = tmd[i].WindCode; md[i].Code = tmd[i].Code; md[i].ActionDay = tmd[i].ActionDay; md[i].Time = tmd[i].Time; md[i].Status = tmd[i].Status; md[i].PreClose = tmd[i].PreClose; md[i].Open = tmd[i].Open; md[i].High = tmd[i].High; md[i].Low = tmd[i].Low; md[i].Match = tmd[i].Match; for (int j = 0; j < 10; j++) { md[i].AskPrice[j] = tmd[i].AskPrice[j]; md[i].AskVol[j] = (int)tmd[i].AskVol[j]; md[i].BidPrice[j] = tmd[i].BidPrice[j]; md[i].BidVol[j] = (int)tmd[i].BidVol[j]; } md[i].NumTrades = (int)(tmd[i].NumTrades); md[i].Volume = (int)(tmd[i].Volume); md[i].Turnover = tmd[i].Turnover; md[i].TotalAskVol = (int)(tmd[i].TotalAskVol); md[i].TotalBidVol = (int)(tmd[i].TotalBidVol); md[i].WeightedAvgAskPrice = tmd[i].WeightedAvgAskPrice; md[i].WeightedAvgBidPrice = tmd[i].WeightedAvgBidPrice; md[i].IOPV = tmd[i].IOPV; md[i].YieldToMaturity = tmd[i].YieldToMaturity; md[i].HighLimited = tmd[i].HighLimited; md[i].LowLimited = tmd[i].LowLimited; tmd[i].Prefix.CopyTo(md[i].Prefix, 0); md[i].Syl1 = tmd[i].Syl1; md[i].Syl2 = tmd[i].Syl2; md[i].SD2 = tmd[i].SD2; } lock (this) { _recvDataCount += tmd.Length; } if (NewMarketData != null) { NewMarketData(md); } } } else if (_source.OrderCache.Count > 0) { TDFOrder[] oc; if (_source.OrderCache.TryDequeue(out oc)) { MarketOrder[] mo = new MarketOrder[oc.Length]; for (int i = 0; i < mo.Length; i++) { mo[i] = new MarketOrder(); mo[i].WindCode = oc[i].WindCode; mo[i].Code = oc[i].Code; mo[i].ActionDay = oc[i].ActionDay; mo[i].Time = oc[i].Time; mo[i].Order = oc[i].Order; mo[i].Price = oc[i].Price; mo[i].Volume = oc[i].Volume; mo[i].OrderKind = oc[i].OrderKind; mo[i].FunctionCode = oc[i].FunctionCode; } lock (this) { _recvDataCount += oc.Length; } if (NewMarketOrder != null) { NewMarketOrder(mo); } } } else if (_source.TransactionCache.Count > 0) { TDFTransaction[] t; if (_source.TransactionCache.TryDequeue(out t)) { MarketTransaction[] mt = new MarketTransaction[t.Length]; for (int i = 0; i < t.Length; i++) { mt[i] = new MarketTransaction(); mt[i].WindCode = t[i].WindCode; mt[i].Code = t[i].Code; mt[i].ActionDay = t[i].ActionDay; mt[i].Time = t[i].Time; mt[i].Index = t[i].Index; mt[i].Price = t[i].Price; mt[i].Volume = t[i].Volume; mt[i].Turnover = t[i].Turnover; mt[i].Flag = t[i].BSFlag; mt[i].OrderKind = t[i].OrderKind; mt[i].FunctionCode = t[i].FunctionCode; mt[i].AskOrder = t[i].AskOrder; mt[i].BidOrder = t[i].BidOrder; } lock (this) { _recvDataCount += t.Length; } if (NewMarketTransction != null) { NewMarketTransction(mt); } } } else if (_source.OrderQueueCache.Count > 0) { TDFOrderQueue[] oq; if (_source.OrderQueueCache.TryDequeue(out oq)) { MarketOrderQueue[] moq = new MarketOrderQueue[oq.Length]; for (int i = 0; i < oq.Length; i++) { moq[i] = new MarketOrderQueue(); moq[i].WindCode = oq[i].WindCode; moq[i].Code = oq[i].Code; moq[i].ActionDay = oq[i].ActionDay; moq[i].Time = oq[i].Time; moq[i].Side = oq[i].Side; moq[i].Price = oq[i].Price; moq[i].Orders = oq[i].Orders; moq[i].Items = oq[i].ABItems; oq[i].ABVolume.CopyTo(moq[i].Volume, 0); } lock (this) { _recvDataCount += oq.Length; } if (NewMarketOrderQueue != null) { NewMarketOrderQueue(moq); } } } else { Thread.Sleep(10); } } else { Thread.Sleep(1000); } } }
/// <summary> /// Strategy enter/exit/filtering rules /// </summary> public override void OnNewBar() { decimal stopMargin = (int)this.GetInputParameter("Catastrophic Stop Loss ticks distance") * this.GetMainChart().Symbol.TickSize; int buySignal = (int)this.GetInputParameter("RSI Buy signal trigger level"); int sellSignal = (int)this.GetInputParameter("RSI Sell signal trigger level"); if (rsiIndicator.GetRSI()[1] <= buySignal && rsiIndicator.GetRSI()[0] > buySignal && this.GetOpenPosition() != 1) { if (this.GetOpenPosition() == 0) { //BUY SIGNAL: Entering long and placing a catastrophic stop loss MarketOrder buyOrder = new MarketOrder(OrderSide.Buy, 1, "Enter long position"); catastrophicStop = new StopOrder(OrderSide.Sell, 1, this.Bars.Close[0] - stopMargin, "Catastrophic stop long exit"); this.InsertOrder(buyOrder); this.InsertOrder(catastrophicStop); } else if (this.GetOpenPosition() == -1) { //BUY SIGNAL: Closing short position and cancelling the catastrophic stop loss order MarketOrder exitShortOrder = new MarketOrder(OrderSide.Buy, 1, "Exit short position (reversal exit signal)"); this.InsertOrder(exitShortOrder); this.CancelOrder(catastrophicStop); } } else if (rsiIndicator.GetRSI()[1] >= sellSignal && rsiIndicator.GetRSI()[0] < sellSignal && this.GetOpenPosition() != -1) { if (this.GetOpenPosition() == 0) { //SELL SIGNAL: Entering short and placing a catastrophic stop loss MarketOrder sellOrder = new MarketOrder(OrderSide.Sell, 1, "Enter short position"); catastrophicStop = new StopOrder(OrderSide.Buy, 1, this.Bars.Close[0] + stopMargin, "Catastrophic stop short exit"); this.InsertOrder(sellOrder); this.InsertOrder(catastrophicStop); } else if (this.GetOpenPosition() == 1) { //SELL SIGNAL: Closing long position and cancelling the catastrophic stop loss order MarketOrder exitLongOrder = new MarketOrder(OrderSide.Sell, 1, "Exit long position (reversal exit signal)"); this.InsertOrder(exitLongOrder); this.CancelOrder(catastrophicStop); } } }
public void GenerateMarginCallOrderTests() { const int quantity = 1000; const decimal leverage = 1m; var orderProcessor = new FakeOrderProcessor(); var portfolio = GetPortfolio(orderProcessor, quantity); portfolio.MarginCallModel = new DefaultMarginCallModel(portfolio, null); var security = GetSecurity(Symbols.AAPL); portfolio.Securities.Add(security); var time = DateTime.Now; const decimal buyPrice = 1m; security.SetMarketPrice(new Tick(time, Symbols.AAPL, buyPrice, buyPrice)); var order = new MarketOrder(Symbols.AAPL, quantity, time) { Price = buyPrice }; var fill = new OrderEvent(order, DateTime.UtcNow, OrderFee.Zero) { FillPrice = buyPrice, FillQuantity = quantity }; orderProcessor.AddOrder(order); var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, order.Time, null); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(null, request)); Assert.AreEqual(portfolio.Cash, fill.FillPrice * fill.FillQuantity); portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var newOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1)) { Price = buyPrice }; var hasSufficientBuyingPower = security.BuyingPowerModel.HasSufficientBuyingPowerForOrder(portfolio, security, newOrder).IsSufficient; Assert.IsFalse(hasSufficientBuyingPower); // now the stock doubles, so we should have margin remaining time = time.AddDays(1); const decimal highPrice = buyPrice * 2; security.SetMarketPrice(new Tick(time, Symbols.AAPL, highPrice, highPrice)); portfolio.InvalidateTotalPortfolioValue(); Assert.AreEqual(quantity, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity * 2, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var anotherOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1)) { Price = highPrice }; hasSufficientBuyingPower = security.BuyingPowerModel.HasSufficientBuyingPowerForOrder(portfolio, security, anotherOrder).IsSufficient; Assert.IsTrue(hasSufficientBuyingPower); // now the stock plummets, so we should have negative margin remaining time = time.AddDays(1); const decimal lowPrice = buyPrice / 2; security.SetMarketPrice(new Tick(time, Symbols.AAPL, lowPrice, lowPrice)); portfolio.InvalidateTotalPortfolioValue(); Assert.AreEqual(-quantity / 2m, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity / 2m, portfolio.TotalPortfolioValue); // this would not cause a margin call due to leverage = 1 bool issueMarginCallWarning; var marginCallOrders = portfolio.MarginCallModel.GetMarginCallOrders(out issueMarginCallWarning); Assert.IsFalse(issueMarginCallWarning); Assert.AreEqual(0, marginCallOrders.Count); // now change the leverage to test margin call warning and margin call logic security.SetLeverage(leverage * 2); // Stock price increase by minimum variation const decimal newPrice = lowPrice + 0.01m; security.SetMarketPrice(new Tick(time, Symbols.AAPL, newPrice, newPrice)); portfolio.InvalidateTotalPortfolioValue(); // this would not cause a margin call, only a margin call warning marginCallOrders = portfolio.MarginCallModel.GetMarginCallOrders(out issueMarginCallWarning); Assert.IsTrue(issueMarginCallWarning); Assert.AreEqual(0, marginCallOrders.Count); // Price drops again to previous low, margin call orders will be issued security.SetMarketPrice(new Tick(time, Symbols.AAPL, lowPrice, lowPrice)); portfolio.InvalidateTotalPortfolioValue(); order = new MarketOrder(Symbols.AAPL, quantity, time) { Price = buyPrice }; fill = new OrderEvent(order, DateTime.UtcNow, OrderFee.Zero) { FillPrice = buyPrice, FillQuantity = quantity }; portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.TotalPortfolioValue); marginCallOrders = portfolio.MarginCallModel.GetMarginCallOrders(out issueMarginCallWarning); Assert.IsTrue(issueMarginCallWarning); Assert.AreEqual(1, marginCallOrders.Count); }
public Order MarketOrder(OrderSide side, double qty, string text) { SingleOrder singleOrder; if (side == OrderSide.Buy) { singleOrder = new MarketOrder(this.sq_Instrument, Side.Buy, qty, text); } else { singleOrder = new MarketOrder(this.sq_Instrument, Side.Sell, qty, text); } singleOrder.Strategy = this.strategyName; Order order = new Order(singleOrder); order.Portfolio = this.portfolio; Map.OQ_SQ_Order[order] = singleOrder; Map.SQ_OQ_Order[singleOrder] = order; return order; }
/// <summary> /// Converts the specified Oanda order into a qc order. /// The 'task' will have a value if we needed to issue a rest call for the stop price, otherwise it will be null /// </summary> private Order ConvertOrder(DataType.Order order) { Order qcOrder; switch (order.type) { case "limit": qcOrder = new LimitOrder(); if (order.side == "buy") { ((LimitOrder)qcOrder).LimitPrice = Convert.ToDecimal(order.lowerBound); } if (order.side == "sell") { ((LimitOrder)qcOrder).LimitPrice = Convert.ToDecimal(order.upperBound); } break; case "stop": qcOrder = new StopLimitOrder(); if (order.side == "buy") { ((StopLimitOrder)qcOrder).LimitPrice = Convert.ToDecimal(order.lowerBound); } if (order.side == "sell") { ((StopLimitOrder)qcOrder).LimitPrice = Convert.ToDecimal(order.upperBound); } break; case "marketIfTouched": //when market reaches the price sell at market. qcOrder = new StopMarketOrder { Price = Convert.ToDecimal(order.price), StopPrice = Convert.ToDecimal(order.price) }; break; case "market": qcOrder = new MarketOrder(); break; default: throw new NotSupportedException("The Oanda order type " + order.type + " is not supported."); } var securityType = _symbolMapper.GetBrokerageSecurityType(order.instrument); qcOrder.Symbol = _symbolMapper.GetLeanSymbol(order.instrument, securityType, Market.Oanda); qcOrder.Quantity = ConvertQuantity(order); qcOrder.Status = OrderStatus.None; qcOrder.BrokerId.Add(order.id.ToString()); var orderByBrokerageId = _orderProvider.GetOrderByBrokerageId(order.id); if (orderByBrokerageId != null) { qcOrder.Id = orderByBrokerageId.Id; } qcOrder.Duration = OrderDuration.Custom; qcOrder.DurationValue = XmlConvert.ToDateTime(order.expiry, XmlDateTimeSerializationMode.Utc); qcOrder.Time = XmlConvert.ToDateTime(order.time, XmlDateTimeSerializationMode.Utc); return(qcOrder); }
public override List <string> OnQuotesReceived(string[] names, CandleDataBidAsk[] quotes, bool isHistoryStartOff) { var events = new List <string>(); if (tickers.Length == 0 || isHistoryStartOff) { return(events); } if (lastTrade == null) { lastTrade = new ThreadSafeTimeStamp(); lastTrade.Touch(); } // секунд с последнего трейда... var timeSince = (DateTime.Now - lastTrade.GetLastHit()).TotalSeconds; if (timeSince < tradeIntervalSec) { return(events); } lastTrade.Touch(); // затребовать все сделки со своим magic List <MarketOrder> orders; GetMarketOrders(out orders, true); var sides = tickers.ToDictionary(t => t, t => 1); if (orders != null) { foreach (var order in orders) { if (sides.ContainsKey(order.Symbol)) { sides[order.Symbol] = -order.Side; } // закрыть старую сделку CloseMarketOrder(order.ID); } } // открыть новые сделки foreach (var tickerSide in sides) { var newOrd = new MarketOrder { Symbol = tickerSide.Key, Side = tickerSide.Value, AccountID = robotContext.AccountInfo.ID, Magic = Magic, Volume = FixedVolume, ExpertComment = "SimpleTradeMachine" }; var rst = robotContext.SendNewOrderRequest(protectedContext.MakeProtectedContext(), RequestUniqueId.Next(), newOrd, OrderType.Market, 0, 0); } return(events); }
public IncomingMessage Visit(Mantle.Fix44.MarketDataIncrementalRefresh msg) { var res = new IncomingMessage(); res.SendingTime = msg.StandardHeader.SendingTime.Value; if (!msg.StandardHeader.SendingTime.HasValue) { _log.Warn("MarketDataResponse is missing SendingTime field: {0}", msg); return(null); } res.MarketData.Value.ServerTime = msg.StandardHeader.SendingTime.Value; if (!msg.Instrument.Symbol.HasValue) { _log.Warn("MarketDataResponse is missing Symbol field: {0}", msg); return(null); } res.MarketData.Value.Symbol = msg.Instrument.Symbol.Value; foreach (Mantle.Fix44.MDEntry entry in msg.MDEntries) { string error; MarketOrder order = MakeOrder(entry, out error); if (order != null) { var diff = new MarketOrderDiff(); diff.Order = order; if (!entry.MDUpdateAction.HasValue) { _log.Warn("Missing MDUpdateAction field: {0}", msg); break; } else if (entry.MDUpdateAction.Value == '0') { diff.Type = DiffType.New; } else if (entry.MDUpdateAction.Value == '1') { diff.Type = DiffType.Change; } else if (entry.MDUpdateAction.Value == '2') { diff.Type = DiffType.Delete; } else { _log.Warn("Invalid value of MDUpdateAction {0}: {1}", entry.MDUpdateAction.Value, msg); break; } if (res.MarketData.Value.Diff == null) { res.MarketData.Value.Diff = new List <MarketOrderDiff>(); } res.MarketData.Value.Diff.Add(diff); continue; } if (error != null) { _log.Warn("{0}: {1}", error, msg); continue; } _log.Warn("Ignoring MDEntry of unkonwn format: {0}", msg); } return(res); }