public AccountTrunk( int maxEvent ) { this.MAX_EVENT = maxEvent; this.events = new Event[this.MAX_EVENT]; this.accounts = new Account[AccountTrunk.MAX_ACCOUNT]; this.securities = new Securities(); this.actAccount = 0; this.actEvent = 0; }
/// <summary> /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. /// </summary> /// <param name="data">Slice object keyed by symbol containing the stock data</param> public override void OnData(Slice data) { Debug($"[{Time}] Warmup: {IsWarmingUp}. Invested: {Portfolio.Invested} {string.Join(",", Securities.Select(pair => $"{pair.Key.Value}:{pair.Value.Price}"))}"); if (IsWarmingUp) { _equityGotTradeBars |= data.Bars.ContainsKey("SPY"); _equityGotQuoteBars |= data.QuoteBars.ContainsKey("SPY"); _cryptoGotTradeBars |= data.Bars.ContainsKey("BTCUSD"); } else { if (!Portfolio.Invested) { AddEquity("AAPL", Resolution.Hour); SetHoldings("BTCUSD", 0.3); } } }
/// <summary> /// Determines whether or not the specified symbol is currently a member of this universe /// </summary> /// <param name="symbol">The symbol whose membership is to be checked</param> /// <returns>True if the specified symbol is part of this universe, false otherwise</returns> public bool ContainsMember(Symbol symbol) { return(Securities.ContainsKey(symbol)); }
/// <summary> /// Create a simple JSON holdings from a Security holding class. /// </summary> /// <param name="holding"></param> public Holding(Securities.SecurityHolding holding) { Symbol = holding.Symbol; Quantity = holding.Quantity; AveragePrice = holding.AveragePrice; MarketPrice = holding.Price; }
/// <summary> /// Perform preorder checks to ensure we have sufficient capital, /// the market is open, and we haven't exceeded maximum realistic orders per day. /// </summary> /// <returns>OrderResponse. If no error, order request is submitted.</returns> private OrderResponse PreOrderChecksImpl(SubmitOrderRequest request) { if (IsWarmingUp) { return(OrderResponse.WarmingUp(request)); } //Most order methods use security objects; so this isn't really used. // todo: Left here for now but should review Security security; if (!Securities.TryGetValue(request.Symbol, out security)) { return(OrderResponse.Error(request, OrderResponseErrorCode.MissingSecurity, "You haven't requested " + request.Symbol.ToString() + " data. Add this with AddSecurity() in the Initialize() Method.")); } //Ordering 0 is useless. if (request.Quantity == 0) { return(OrderResponse.ZeroQuantity(request)); } if (Math.Abs(request.Quantity) < security.SymbolProperties.LotSize) { return(OrderResponse.Error(request, OrderResponseErrorCode.OrderQuantityLessThanLoteSize, $"Unable to {request.OrderRequestType.ToString().ToLower()} order with id {request.OrderId} which quantity ({Math.Abs(request.Quantity)}) is less than lot size ({security.SymbolProperties.LotSize}).")); } if (!security.IsTradable) { return(OrderResponse.Error(request, OrderResponseErrorCode.NonTradableSecurity, "The security with symbol '" + request.Symbol.ToString() + "' is marked as non-tradable.")); } var price = security.Price; //Check the exchange is open before sending a market on close orders if (request.OrderType == OrderType.MarketOnClose && !security.Exchange.ExchangeOpen) { return(OrderResponse.Error(request, OrderResponseErrorCode.ExchangeNotOpen, request.OrderType + " order and exchange not open.")); } //Check the exchange is open before sending a exercise orders if (request.OrderType == OrderType.OptionExercise && !security.Exchange.ExchangeOpen) { return(OrderResponse.Error(request, OrderResponseErrorCode.ExchangeNotOpen, request.OrderType + " order and exchange not open.")); } if (price == 0) { return(OrderResponse.Error(request, OrderResponseErrorCode.SecurityPriceZero, request.Symbol.ToString() + ": asset price is $0. If using custom data make sure you've set the 'Value' property.")); } // check quote currency existence/conversion rate on all orders Cash quoteCash; var quoteCurrency = security.QuoteCurrency.Symbol; if (!Portfolio.CashBook.TryGetValue(quoteCurrency, out quoteCash)) { return(OrderResponse.Error(request, OrderResponseErrorCode.QuoteCurrencyRequired, request.Symbol.Value + ": requires " + quoteCurrency + " in the cashbook to trade.")); } if (security.QuoteCurrency.ConversionRate == 0m) { return(OrderResponse.Error(request, OrderResponseErrorCode.ConversionRateZero, request.Symbol.Value + ": requires " + quoteCurrency + " to have a non-zero conversion rate. This can be caused by lack of data.")); } // need to also check base currency existence/conversion rate on forex orders if (security.Type == SecurityType.Forex || security.Type == SecurityType.Crypto) { Cash baseCash; var baseCurrency = ((IBaseCurrencySymbol)security).BaseCurrencySymbol; if (!Portfolio.CashBook.TryGetValue(baseCurrency, out baseCash)) { return(OrderResponse.Error(request, OrderResponseErrorCode.ForexBaseAndQuoteCurrenciesRequired, request.Symbol.Value + ": requires " + baseCurrency + " and " + quoteCurrency + " in the cashbook to trade.")); } if (baseCash.ConversionRate == 0m) { return(OrderResponse.Error(request, OrderResponseErrorCode.ForexConversionRateZero, request.Symbol.Value + ": requires " + baseCurrency + " and " + quoteCurrency + " to have non-zero conversion rates. This can be caused by lack of data.")); } } //Make sure the security has some data: if (!security.HasData) { return(OrderResponse.Error(request, OrderResponseErrorCode.SecurityHasNoData, "There is no data for this symbol yet, please check the security.HasData flag to ensure there is at least one data point.")); } // We've already processed too many orders: max 10k if (!LiveMode && Transactions.OrdersCount > _maxOrders) { Status = AlgorithmStatus.Stopped; return(OrderResponse.Error(request, OrderResponseErrorCode.ExceededMaximumOrders, string.Format("You have exceeded maximum number of orders ({0}), for unlimited orders upgrade your account.", _maxOrders))); } if (request.OrderType == OrderType.OptionExercise) { if (security.Type != SecurityType.Option) { return(OrderResponse.Error(request, OrderResponseErrorCode.NonExercisableSecurity, "The security with symbol '" + request.Symbol.ToString() + "' is not exercisable.")); } if (security.Holdings.IsShort) { return(OrderResponse.Error(request, OrderResponseErrorCode.UnsupportedRequestType, "The security with symbol '" + request.Symbol.ToString() + "' has a short option position. Only long option positions are exercisable.")); } if (request.Quantity > security.Holdings.Quantity) { return(OrderResponse.Error(request, OrderResponseErrorCode.UnsupportedRequestType, "Cannot exercise more contracts of '" + request.Symbol.ToString() + "' than is currently available in the portfolio. ")); } if (request.Quantity <= 0.0m) { OrderResponse.ZeroQuantity(request); } } if (request.OrderType == OrderType.MarketOnClose) { var nextMarketClose = security.Exchange.Hours.GetNextMarketClose(security.LocalTime, false); // must be submitted with at least 10 minutes in trading day, add buffer allow order submission var latestSubmissionTime = nextMarketClose.Subtract(Orders.MarketOnCloseOrder.DefaultSubmissionTimeBuffer); if (!security.Exchange.ExchangeOpen || Time > latestSubmissionTime) { // tell the user we require a 16 minute buffer, on minute data in live a user will receive the 3:44->3:45 bar at 3:45, // this is already too late to submit one of these orders, so make the user do it at the 3:43->3:44 bar so it's submitted // to the brokerage before 3:45. return(OrderResponse.Error(request, OrderResponseErrorCode.MarketOnCloseOrderTooLate, "MarketOnClose orders must be placed with at least a 16 minute buffer before market close.")); } } // passes all initial order checks return(OrderResponse.Success(request)); }
protected override void OnProcessMessage(Message message) { //_historyMessageAdapter.UpdateCurrentTime(message.LocalTime); switch (message.Type) { case MessageTypes.Connect: { if (message.Adapter == MarketDataAdapter) { break; } _isHistory = true; _isInitialization = true; _connectTime = message.LocalTime; _strategy.SetIsInitialization(true); _historyMessageAdapter .SecurityProvider .LookupAll() .ForEach(s => SendOutMessage(s.ToMessage())); break; } case (MessageTypes)(-1): { new ChartAutoRangeCommand(false).Process(_strategy); _strategy.PositionManager.Positions = _sessionStrategy.Positions.Select(p => p.Position).ToList(); if (_onlyInitialize) { if (message.Adapter == MarketDataAdapter) { new StopStrategyCommand(_strategy).Process(this); } return; } _historyMessageAdapter.StopDate = DateTimeOffset.MaxValue; _historyMessageAdapter.MarketTimeChangedInterval = TimeSpan.FromMilliseconds(10); var messages = new List <Message>(); messages.AddRange(_realConnector.Trades.Select(t => t.ToMessage())); messages.AddRange(_realConnector.Orders.Select(o => o.ToMessage())); messages.AddRange(_realConnector.OrderRegisterFails.Select(o => o.ToMessage())); messages.AddRange(_realConnector.OrderCancelFails.Select(o => o.ToMessage())); messages.AddRange(_realConnector.MyTrades.Select(t => t.ToMessage())); messages.ForEach(SendOutMessage); _isHistory = false; return; } case MessageTypes.Execution: { var execMsg = (ExecutionMessage)message; if (execMsg.ExecutionType == ExecutionTypes.Tick && !_isHistory && _isInitialization) { ProcessTime(execMsg.ServerTime, execMsg.SecurityId.BoardCode); } break; } default: { var candleMsg = message as CandleMessage; if (candleMsg == null) { break; } if (!_isHistory) { break; } var stocksharpId = CreateSecurityId(candleMsg.SecurityId.SecurityCode, candleMsg.SecurityId.BoardCode); var security = Securities.FirstOrDefault(s => s.Id.CompareIgnoreCase(stocksharpId)); if (security == null) { throw new InvalidOperationException(LocalizedStrings.Str704Params.Put(candleMsg.SecurityId)); } var volumeStep = security.VolumeStep ?? 1m; var decimals = volumeStep.GetCachedDecimals(); var trades = candleMsg.ToTrades(volumeStep, decimals); foreach (var executionMessage in trades) { base.OnProcessMessage(executionMessage); } return; } } base.OnProcessMessage(message); }
/// <summary> /// Submit a new order for quantity of symbol using type order. /// </summary> /// <param name="type">Buy/Sell Limit or Market Order Type.</param> /// <param name="symbol">Symbol of the MarketType Required.</param> /// <param name="quantity">Number of shares to request.</param> /// <param name="asynchronous">Send the order asynchrously (false). Otherwise we'll block until it fills</param> /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param> /// <seealso cref="Order(string, double, OrderType)"/> public int Order(string symbol, int quantity, OrderType type = OrderType.Market, bool asynchronous = false, string tag = "") { //Add an order to the transacion manager class: var orderId = -1; decimal price = 0; //Ordering 0 is useless. if (quantity == 0 || symbol == null || symbol == "") { return(-1); } //Internals use upper case symbols. symbol = symbol.ToUpper(); //If we're not tracking this symbol: throw error: if (!Securities.ContainsKey(symbol) && !_sentNoDataError) { _sentNoDataError = true; Error("You haven't requested " + symbol + " data. Add this with AddSecurity() in the Initialize() Method."); } //Set a temporary price for validating order for market orders: var security = Securities[symbol]; price = security.Price; if (price == 0) { Error("Asset price is $0. If using custom data make sure you've set the 'Value' property."); return(-1); } //Make sure the security has some data: if (!security.HasData) { Error("There is no data for this symbol yet, please check the security.HasData flag to ensure there is at least one data point."); return(-1); } //Check the exchange is open before sending a market order. if (type == OrderType.Market && !security.Exchange.ExchangeOpen) { Error("Market order and exchange not open"); return(-3); } //We've already processed too many orders: max 100 per day or the memory usage explodes if (Orders.Count > (_endDate - _startDate).TotalDays * 100) { Error("You have exceeded 100 orders per day"); return(-5); } //Add the order and create a new order Id. orderId = Transactions.AddOrder(new Order(symbol, security.Type, quantity, type, Time, price, tag)); //Wait for the order event to process: //Enqueue means send to order queue but don't wait for response: if (!asynchronous && type == OrderType.Market) { //Wait for the market order to fill. //This is processed in a parallel thread. while (!Transactions.Orders.ContainsKey(orderId) || (Transactions.Orders[orderId].Status != OrderStatus.Filled && Transactions.Orders[orderId].Status != OrderStatus.Invalid && Transactions.Orders[orderId].Status != OrderStatus.Canceled) || _processingOrder) { Thread.Sleep(1); } } return(orderId); }
public AccountTrunk() { this.accounts = new Account[AccountTrunk.MAX_ACCOUNT]; this.securities = new Securities(); this.actAccount = 0; }
private void SetSecurityInPanel(PanelGraph panel, Securities sec) { this.SetSecurityInPanel(panel, sec.Code, sec.Class.Code); }
public void GetHistory(Selection parameters, HistoryAnswerHandler callback) { if (_session == null) { throw new ApplicationException("Can't load history. LMAX data feed is not connected."); } var symbol = parameters.Symbol.ToUpper(); var instrument = Securities.FirstOrDefault(i => i.Symbol.Equals(symbol, StringComparison.OrdinalIgnoreCase)); if (instrument == null) { Logger.Warning($"Invalid symbol {parameters.Symbol} passed for history request over {Name} feed"); return; } lock (_historyRequestHandlers) { if (parameters.To == DateTime.MinValue || parameters.To > DateTime.UtcNow) { parameters.To = DateTime.UtcNow; } //calculate start time if (parameters.From == DateTime.MinValue && parameters.BarCount != int.MaxValue) { if (parameters.BarCount < 3) { callback(parameters, new List <Bar>()); return; } if (parameters.To > DateTime.UtcNow) { parameters.To = DateTime.UtcNow; } if (parameters.Timeframe == Timeframe.Minute) { parameters.From = parameters.To.AddMinutes(-1 * 3 * parameters.BarCount * parameters.TimeFactor); } else if (parameters.Timeframe == Timeframe.Hour) { parameters.From = parameters.To.AddHours(-1 * 3 * parameters.BarCount * parameters.TimeFactor); } else if (parameters.Timeframe == Timeframe.Day) { parameters.From = parameters.To.AddDays(-1 * 2 * parameters.BarCount * parameters.TimeFactor); } else if (parameters.Timeframe == Timeframe.Month) { parameters.From = parameters.To.AddDays(-1 * parameters.BarCount * parameters.TimeFactor * 31); } } parameters.From = TimeZoneInfo.ConvertTimeFromUtc(parameters.From, TimeZoneInfo); parameters.To = TimeZoneInfo.ConvertTimeFromUtc(parameters.To, TimeZoneInfo); var bidParams = (Selection)parameters.Clone(); bidParams.BidAsk = PriceType.Bid; var id = ++_id; _historyRequestHandlers.Add(id, callback); _originalHistoryRequestParameters.Add(id, bidParams); _session?.RequestHistoricMarketData(new AggregateHistoricMarketDataRequest(id, instrument.SecurityId, bidParams.From, bidParams.To, FromPeriodToResolution(bidParams.Timeframe), Format.Csv, Option.Bid), () => { }, FailureCallback); var askParams = (Selection)parameters.Clone(); askParams.BidAsk = PriceType.Ask; id = ++_id; _historyRequestHandlers.Add(id, callback); _originalHistoryRequestParameters.Add(id, askParams); _session?.RequestHistoricMarketData(new AggregateHistoricMarketDataRequest(id, instrument.SecurityId, askParams.From, askParams.To, FromPeriodToResolution(askParams.Timeframe), Format.Csv, Option.Ask), () => { }, FailureCallback); // /*var askHistParams = (Selection)parameters.Clone(); * askHistParams.BidAsk = PriceType.Unspecified; * id = ++_id; * _historyRequestHandlers.Add(id, callback); * _originalHistoryRequestParameters.Add(id, askHistParams); * * _session?.RequestHistoricMarketData(new TopOfBookHistoricMarketDataRequest(id, instrument.SecurityId, askParams.From, askParams.To, Format.Csv), * () => { }, FailureCallback);*/ } }
/// <summary> /// Add a security to the feed so it receives events /// </summary> /// <param name="security">Security</param> public void AddSecurity(Security security) { Securities.Add(security.Symbol, security); }
/// <summary> /// Remove security to the feed so it no longer receives events /// </summary> /// <param name="security">Security</param> public void RemoveSecurity(Security security) { Securities.Remove(security.Symbol); }
static void Main(string[] args) { User user = new User(); Business business = new Business(); while (true) { user.displayMenu(); Console.WriteLine(); Console.Write("Enter options > "); int options = Convert.ToInt32(Console.ReadLine()); string title; string status; string id; int price; List <Securities> list; switch (options) { case 1: Console.Write("Enter title > "); title = Console.ReadLine().Trim(); Console.Write("Enter status > "); status = Console.ReadLine().Trim(); Console.Write("Enter price > "); price = Convert.ToInt32(Console.ReadLine()); business.add(title, status, price, DateTime.Now); break; case 2: Console.Write("Enter id > "); id = Console.ReadLine().Trim(); business.remove(id); break; case 3: try { Console.Write("Enter id > "); id = Console.ReadLine().Trim(); Console.Write("Enter title > "); title = Console.ReadLine().Trim(); Console.Write("Enter status > "); status = Console.ReadLine().Trim(); Console.Write("Enter price > "); price = Convert.ToInt32(Console.ReadLine()); Console.Write("Enter date y m d > "); string[] date = Console.ReadLine().Split(" "); DateTime dateIn = new DateTime(Convert.ToInt32(date[0]), Convert.ToInt32(date[1]), Convert.ToInt32(date[2]) + 1); business.edit(id, new Securities { id = id, title = title, status = status, price = price, date = dateIn }); } catch (Exception e) { Console.WriteLine("Error: " + e); } break; case 4: Console.Write("Enter id > "); id = Console.ReadLine().Trim(); try { Securities securities = business.show(id); Console.WriteLine(); Console.WriteLine(securities.id + " " + securities.title + " " + securities.status + " " + securities.price + " " + securities.date); } catch (Exception e) { Console.WriteLine("Not found 404"); } Console.WriteLine(); break; case 5: list = business.showAll(); Console.WriteLine(); foreach (var item in list) { Console.WriteLine(item.id + " " + item.title + " " + item.status + " " + item.price + " " + item.date); Console.WriteLine(); } break; case 6: Console.Write("Enter start date y m d > "); string[] dateS = Console.ReadLine().Split(" "); Console.WriteLine(); Console.Write("Enter end date y m d > "); string[] dateE = Console.ReadLine().Split(" "); DateTime datS = new DateTime(Convert.ToInt32(dateS[0]), Convert.ToInt32(dateS[1]), Convert.ToInt32(dateS[2])); DateTime datE = new DateTime(Convert.ToInt32(dateE[0]), Convert.ToInt32(dateE[1]), Convert.ToInt32(dateE[2])); Console.Write("Enter status ([y (is bought)]/[n (is sold)]) > "); status = Console.ReadLine().Trim(); Console.Write("Enter title > "); title = Console.ReadLine().Trim(); while (true) { if (status != "y" && status != "n") { Console.WriteLine("Incorrect status"); Console.Write("Enter status ([y (is bought)]/[n (is sold)]) > "); status = Console.ReadLine().Trim(); } else { break; } } bool isBoutht = status == "y"; Console.WriteLine(business.getSecByTime(datS, datE, isBoutht, title)); break; default: Console.WriteLine("Incorrect option"); break; } } }
/// <summary> /// Invoked at the end of every time step. This allows the algorithm /// to process events before advancing to the next time step. /// </summary> public void OnEndOfTimeStep() { if (_pendingUniverseAdditions.Count + _pendingUserDefinedUniverseSecurityAdditions.Count == 0) { // no point in looping through everything if there's no pending changes return; } // rewrite securities w/ derivatives to be in raw mode lock (_pendingUniverseAdditionsLock) { foreach (var security in Securities.Select(kvp => kvp.Value).Union(_pendingUserDefinedUniverseSecurityAdditions.Keys)) { // check for any derivative securities and mark the underlying as raw if (Securities.Any(skvp => skvp.Key.HasUnderlyingSymbol(security.Symbol))) { // set data mode raw and default volatility model ConfigureUnderlyingSecurity(security); } if (security.Symbol.HasUnderlying) { Security underlyingSecurity; var underlyingSymbol = security.Symbol.Underlying; // create the underlying security object if it doesn't already exist if (!Securities.TryGetValue(underlyingSymbol, out underlyingSecurity)) { underlyingSecurity = AddSecurity(underlyingSymbol.SecurityType, underlyingSymbol.Value, security.Resolution, underlyingSymbol.ID.Market, false, 0, security.IsExtendedMarketHours); } // set data mode raw and default volatility model ConfigureUnderlyingSecurity(underlyingSecurity); // set the underying security on the derivative -- we do this in two places since it's possible // to do AddOptionContract w/out the underlying already added and normalized properly var derivative = security as IDerivativeSecurity; if (derivative != null) { derivative.Underlying = underlyingSecurity; } } } // add securities to their respective user defined universes foreach (var kvp in _pendingUserDefinedUniverseSecurityAdditions) { var security = kvp.Key; var userDefinedUniverse = kvp.Value; userDefinedUniverse.Add(security.Symbol); } // finally add any pending universes, this will make them available to the data feed foreach (var universe in _pendingUniverseAdditions) { UniverseManager.Add(universe.Configuration.Symbol, universe); } _pendingUniverseAdditions.Clear(); _pendingUserDefinedUniverseSecurityAdditions.Clear(); } }
public void AddSecurities(Securities sec) { secs.Add(sec); }
/// <summary> /// Create a simple JSON holdings from a Security holding class. /// </summary> /// <param name="holding"></param> public Holding(Securities.SecurityHolding holding) { this.Symbol = holding.Symbol; this.Quantity = holding.Quantity; this.AveragePrice = holding.AveragePrice; this.MarketPrice = holding.Price; }
/// <summary> /// Perform preorder checks to ensure we have sufficient capital, /// the market is open, and we haven't exceeded maximum realistic orders per day. /// </summary> /// <returns>Negative order errors or zero for pass.</returns> private int PreOrderChecks(string symbol, int quantity, OrderType type) { //Ordering 0 is useless. if (quantity == 0 || string.IsNullOrEmpty(symbol)) { return(-1); } //Internals use upper case symbols. symbol = symbol.ToUpper(); //If we're not tracking this symbol: throw error: if (!Securities.ContainsKey(symbol) && !_sentNoDataError) { _sentNoDataError = true; Error("You haven't requested " + symbol + " data. Add this with AddSecurity() in the Initialize() Method."); return(-1); } //Set a temporary price for validating order for market orders: var security = Securities[symbol]; var price = security.Price; //Check the exchange is open before sending a market on close orders //Allow market orders, they'll just execute when the exchange reopens if (type == OrderType.MarketOnClose && !security.Exchange.ExchangeOpen) { Error(type + " order and exchange not open."); return(-3); } if (price == 0) { Error(symbol + ": asset price is $0. If using custom data make sure you've set the 'Value' property."); return(-1); } if (security.Type == SecurityType.Forex) { // for forex pairs we need to verify that the conversions to USD have values as well string baseCurrency, quoteCurrency; Forex.DecomposeCurrencyPair(security.Symbol, out baseCurrency, out quoteCurrency); // verify they're in the portfolio Cash baseCash, quoteCash; if (!Portfolio.CashBook.TryGetValue(baseCurrency, out baseCash) || !Portfolio.CashBook.TryGetValue(quoteCurrency, out quoteCash)) { Error(symbol + ": requires " + baseCurrency + " and " + quoteCurrency + " in the cashbook to trade."); return(-1); } // verify we have conversion rates for each leg of the pair back into the account currency if (baseCash.ConversionRate == 0m || quoteCash.ConversionRate == 0m) { Error(symbol + ": requires " + baseCurrency + " and " + quoteCurrency + " to have non-zero conversion rates. This can be caused by lack of data."); return(-1); } } //Make sure the security has some data: if (!security.HasData) { Error("There is no data for this symbol yet, please check the security.HasData flag to ensure there is at least one data point."); return(-1); } //We've already processed too many orders: max 100 per day or the memory usage explodes if (Transactions.OrdersCount > _maxOrders) { Error(string.Format("You have exceeded maximum number of orders ({0}), for unlimited orders upgrade your account.", _maxOrders)); _quit = true; return(-5); } if (type == OrderType.MarketOnClose) { // must be submitted with at least 10 minutes in trading day, add buffer allow order submission var latestSubmissionTime = (Time.Date + security.Exchange.MarketClose).AddMinutes(-10.75); if (Time > latestSubmissionTime) { // tell the user we require an 11 minute buffer, on minute data in live a user will receive the 3:49->3:50 bar at 3:50, // this is already too late to submit one of these orders, so make the user do it at the 3:48->3:49 bar so it's submitted // to the brokerage before 3:50. Error("MarketOnClose orders must be placed with at least a 11 minute buffer before market close."); return(-6); } } return(0); }
/// <summary> /// Add specified data to required list. QC will funnel this data to the handle data routine. /// </summary> /// <param name="securityType">MarketType Type: Equity, Commodity, Future or FOREX</param> /// <param name="symbol">Symbol Reference for the MarketType</param> /// <param name="resolution">Resolution of the Data Required</param> /// <param name="fillDataForward">When no data available on a tradebar, return the last data that was generated</param> /// <param name="leverage">Custom leverage per security</param> /// <param name="extendedMarketHours">Extended market hours</param> /// <remarks> AddSecurity(SecurityType securityType, string symbol, Resolution resolution, bool fillDataForward, decimal leverage, bool extendedMarketHours)</remarks> public void AddSecurity(SecurityType securityType, string symbol, Resolution resolution, bool fillDataForward, decimal leverage, bool extendedMarketHours) { try { if (_locked) { throw new Exception("Algorithm.AddSecurity(): Cannot add another security after algorithm running."); } symbol = symbol.ToUpper(); //If it hasn't been set, use some defaults based on the portfolio type: if (leverage <= 0) { switch (securityType) { case SecurityType.Equity: leverage = 2; //Cash Ac. = 1, RegT Std = 2 or PDT = 4. break; case SecurityType.Forex: leverage = 50; break; } } //Add the symbol to Data Manager -- generate unified data streams for algorithm events var config = SubscriptionManager.Add(securityType, symbol, resolution, fillDataForward, extendedMarketHours); Security security; switch (config.SecurityType) { case SecurityType.Equity: security = new Equity(config, leverage, false); break; case SecurityType.Forex: // decompose the symbol into each currency pair string baseCurrency, quoteCurrency; QuantConnect.Securities.Forex.Forex.DecomposeCurrencyPair(symbol, out baseCurrency, out quoteCurrency); if (!Portfolio.CashBook.ContainsKey(baseCurrency)) { // since we have none it's safe to say the conversion is zero Portfolio.CashBook.Add(baseCurrency, 0, 0); } if (!Portfolio.CashBook.ContainsKey(quoteCurrency)) { // since we have none it's safe to say the conversion is zero Portfolio.CashBook.Add(quoteCurrency, 0, 0); } security = new Forex(Portfolio.CashBook[quoteCurrency], config, leverage, false); break; default: case SecurityType.Base: security = new Security(config, leverage, false); break; } //Add the symbol to Securities Manager -- manage collection of portfolio entities for easy access. Securities.Add(config.Symbol, security); } catch (Exception err) { Error("Algorithm.AddSecurity(): " + err.Message); } }
/// <summary> /// Adds the security to the user defined universe /// </summary> /// <param name="security">The security to add</param> /// <param name="configurations">The <see cref="SubscriptionDataConfig"/> instances we want to add</param> private void AddToUserDefinedUniverse( Security security, List <SubscriptionDataConfig> configurations) { var subscription = configurations.First(); // if we are adding a non-internal security which already has an internal feed, we remove it first Security existingSecurity; if (Securities.TryGetValue(security.Symbol, out existingSecurity)) { if (!subscription.IsInternalFeed && existingSecurity.IsInternalFeed()) { var securityUniverse = UniverseManager.Select(x => x.Value).OfType <UserDefinedUniverse>().FirstOrDefault(x => x.Members.ContainsKey(security.Symbol)); securityUniverse?.Remove(security.Symbol); Securities.Remove(security.Symbol); } } Securities.Add(security); // add this security to the user defined universe Universe universe; var universeSymbol = UserDefinedUniverse.CreateSymbol(security.Type, security.Symbol.ID.Market); lock (_pendingUniverseAdditionsLock) { if (!UniverseManager.TryGetValue(universeSymbol, out universe)) { universe = _pendingUniverseAdditions.FirstOrDefault(x => x.Configuration.Symbol == universeSymbol); if (universe == null) { // create a new universe, these subscription settings don't currently get used // since universe selection proper is never invoked on this type of universe var uconfig = new SubscriptionDataConfig(subscription, symbol: universeSymbol, isInternalFeed: true, fillForward: false); if (security.Type == SecurityType.Base) { // set entry in market hours database for the universe subscription to match the custom data var symbolString = MarketHoursDatabase.GetDatabaseSymbolKey(uconfig.Symbol); MarketHoursDatabase.SetEntry(uconfig.Market, symbolString, uconfig.SecurityType, security.Exchange.Hours, uconfig.DataTimeZone); } universe = new UserDefinedUniverse(uconfig, new UniverseSettings( subscription.Resolution, security.Leverage, subscription.FillDataForward, subscription.ExtendedMarketHours, TimeSpan.Zero), QuantConnect.Time.MaxTimeSpan, new List <Symbol>()); _pendingUniverseAdditions.Add(universe); } } } var userDefinedUniverse = universe as UserDefinedUniverse; if (userDefinedUniverse != null) { lock (_pendingUniverseAdditionsLock) { _pendingUserDefinedUniverseSecurityAdditions.Add( new UserDefinedUniverseAddition(userDefinedUniverse, configurations, security)); } } else { // should never happen, someone would need to add a non-user defined universe with this symbol throw new Exception("Expected universe with symbol '" + universeSymbol.Value + "' to be of type UserDefinedUniverse."); } }
/// <summary> /// Adds the specified security to this universe /// </summary> /// <param name="utcTime">The current utc date time</param> /// <param name="security">The security to be added</param> /// <returns>True if the security was successfully added, /// false if the security was already in the universe</returns> internal virtual bool AddMember(DateTime utcTime, Security security) { return(Securities.TryAdd(security.Symbol, new Member(utcTime, security))); }
/// <summary> /// Invoked at the end of every time step. This allows the algorithm /// to process events before advancing to the next time step. /// </summary> public void OnEndOfTimeStep() { if (_pendingUniverseAdditions.Count + _pendingUserDefinedUniverseSecurityAdditions.Count == 0) { // no point in looping through everything if there's no pending changes return; } var requiredHistoryRequests = new Dictionary <Security, Resolution>(); // rewrite securities w/ derivatives to be in raw mode lock (_pendingUniverseAdditionsLock) { foreach (var security in Securities.Select(kvp => kvp.Value).Union( _pendingUserDefinedUniverseSecurityAdditions.Select(x => x.Security))) { // check for any derivative securities and mark the underlying as raw if (Securities.Any(skvp => skvp.Key.SecurityType != SecurityType.Base && skvp.Key.HasUnderlyingSymbol(security.Symbol))) { // set data mode raw and default volatility model ConfigureUnderlyingSecurity(security); } var configs = SubscriptionManager.SubscriptionDataConfigService .GetSubscriptionDataConfigs(security.Symbol); if (security.Symbol.HasUnderlying && security.Symbol.SecurityType != SecurityType.Base) { Security underlyingSecurity; var underlyingSymbol = security.Symbol.Underlying; var resolution = configs.GetHighestResolution(); // create the underlying security object if it doesn't already exist if (!Securities.TryGetValue(underlyingSymbol, out underlyingSecurity)) { underlyingSecurity = AddSecurity(underlyingSymbol.SecurityType, underlyingSymbol.Value, resolution, underlyingSymbol.ID.Market, false, 0, configs.IsExtendedMarketHours()); } // set data mode raw and default volatility model ConfigureUnderlyingSecurity(underlyingSecurity); if (LiveMode && underlyingSecurity.GetLastData() == null) { if (requiredHistoryRequests.ContainsKey(underlyingSecurity)) { // lets request the higher resolution var currentResolutionRequest = requiredHistoryRequests[underlyingSecurity]; if (currentResolutionRequest != Resolution.Minute && // Can not be less than Minute resolution < currentResolutionRequest) { requiredHistoryRequests[underlyingSecurity] = (Resolution)Math.Max((int)resolution, (int)Resolution.Minute); } } else { requiredHistoryRequests.Add(underlyingSecurity, (Resolution)Math.Max((int)resolution, (int)Resolution.Minute)); } } // set the underlying security on the derivative -- we do this in two places since it's possible // to do AddOptionContract w/out the underlying already added and normalized properly var derivative = security as IDerivativeSecurity; if (derivative != null) { derivative.Underlying = underlyingSecurity; } } } if (!requiredHistoryRequests.IsNullOrEmpty()) { // Create requests var historyRequests = Enumerable.Empty <HistoryRequest>(); foreach (var byResolution in requiredHistoryRequests.GroupBy(x => x.Value)) { historyRequests = historyRequests.Concat( CreateBarCountHistoryRequests(byResolution.Select(x => x.Key.Symbol), 3, byResolution.Key)); } // Request data var historicLastData = History(historyRequests); historicLastData.PushThrough(x => { var security = requiredHistoryRequests.Keys.FirstOrDefault(y => y.Symbol == x.Symbol); security?.Cache.AddData(x); }); } // add subscriptionDataConfig to their respective user defined universes foreach (var userDefinedUniverseAddition in _pendingUserDefinedUniverseSecurityAdditions) { foreach (var subscriptionDataConfig in userDefinedUniverseAddition.SubscriptionDataConfigs) { userDefinedUniverseAddition.Universe.Add(subscriptionDataConfig); } } // finally add any pending universes, this will make them available to the data feed foreach (var universe in _pendingUniverseAdditions) { UniverseManager.Add(universe.Configuration.Symbol, universe); } _pendingUniverseAdditions.Clear(); _pendingUserDefinedUniverseSecurityAdditions.Clear(); } }
private IEnumerable <OrderTicket> GenerateOrders(OptionStrategy strategy, int strategyQuantity) { var orders = new List <OrderTicket>(); // setting up the tag text for all orders of one strategy var strategyTag = strategy.Name + " (" + strategyQuantity.ToString() + ")"; // walking through all option legs and issuing orders if (strategy.OptionLegs != null) { foreach (var optionLeg in strategy.OptionLegs) { var optionSeq = Securities.Where(kv => kv.Key.Underlying == strategy.Underlying && kv.Key.ID.OptionRight == optionLeg.Right && kv.Key.ID.Date == optionLeg.Expiration && kv.Key.ID.StrikePrice == optionLeg.Strike); if (optionSeq.Count() != 1) { var error = string.Format("Couldn't find the option contract in algorithm securities list. Underlying: {0}, option {1}, strike {2}, expiration: {3}", strategy.Underlying.ToString(), optionLeg.Right.ToString(), optionLeg.Strike.ToString(), optionLeg.Expiration.ToString()); throw new InvalidOperationException(error); } var option = optionSeq.First().Key; switch (optionLeg.OrderType) { case OrderType.Market: var marketOrder = MarketOrder(option, optionLeg.Quantity * strategyQuantity, tag: strategyTag); orders.Add(marketOrder); break; case OrderType.Limit: var limitOrder = LimitOrder(option, optionLeg.Quantity * strategyQuantity, optionLeg.OrderPrice, tag: strategyTag); orders.Add(limitOrder); break; default: throw new InvalidOperationException("Order type is not supported in option strategy: " + optionLeg.OrderType.ToString()); } } } // walking through all underlying legs and issuing orders if (strategy.UnderlyingLegs != null) { foreach (var underlyingLeg in strategy.UnderlyingLegs) { if (!Securities.ContainsKey(strategy.Underlying)) { var error = string.Format("Couldn't find the option contract underlying in algorithm securities list. Underlying: {0}", strategy.Underlying.ToString()); throw new InvalidOperationException(error); } switch (underlyingLeg.OrderType) { case OrderType.Market: var marketOrder = MarketOrder(strategy.Underlying, underlyingLeg.Quantity * strategyQuantity, tag: strategyTag); orders.Add(marketOrder); break; case OrderType.Limit: var limitOrder = LimitOrder(strategy.Underlying, underlyingLeg.Quantity * strategyQuantity, underlyingLeg.OrderPrice, tag: strategyTag); orders.Add(limitOrder); break; default: throw new InvalidOperationException("Order type is not supported in option strategy: " + underlyingLeg.OrderType.ToString()); } } } return(orders); }
/// <summary> /// Gets <see cref="OptionHistory"/> object for a given symbol, date and resolution /// </summary> /// <param name="symbol">The symbol to retrieve historical option data for</param> /// <param name="start">The history request start time</param> /// <param name="end">The history request end time. Defaults to 1 day if null</param> /// <param name="resolution">The resolution to request</param> /// <returns>A <see cref="OptionHistory"/> object that contains historical option data.</returns> public OptionHistory GetOptionHistory(Symbol symbol, DateTime start, DateTime?end = null, Resolution?resolution = null) { if (!end.HasValue || end.Value == start) { end = start.AddDays(1); } // Load a canonical option Symbol if the user provides us with an underlying Symbol if (!symbol.SecurityType.IsOption()) { var option = AddOption(symbol, resolution, symbol.ID.Market); // Allow 20 strikes from the money for futures. No expiry filter is applied // so that any future contract provided will have data returned. if (symbol.SecurityType == SecurityType.Future && symbol.IsCanonical()) { throw new ArgumentException("The Future Symbol provided is a canonical Symbol (i.e. a Symbol representing all Futures), which is not supported at this time. " + "If you are using the Symbol accessible from `AddFuture(...)`, use the Symbol from `AddFutureContract(...)` instead. " + "You can use `qb.FutureOptionChainProvider(canonicalFuture, datetime)` to get a list of futures contracts for a given date, and add them to your algorithm with `AddFutureContract(symbol, Resolution)`."); } if (symbol.SecurityType == SecurityType.Future && !symbol.IsCanonical()) { option.SetFilter(universe => universe.Strikes(-10, +10)); } symbol = option.Symbol; } IEnumerable <Symbol> symbols; if (symbol.IsCanonical()) { // canonical symbol, lets find the contracts var option = Securities[symbol] as Option; var resolutionToUseForUnderlying = resolution ?? SubscriptionManager.SubscriptionDataConfigService .GetSubscriptionDataConfigs(symbol) .GetHighestResolution(); if (!Securities.ContainsKey(symbol.Underlying)) { if (symbol.Underlying.SecurityType == SecurityType.Equity) { // only add underlying if not present AddEquity(symbol.Underlying.Value, resolutionToUseForUnderlying); } if (symbol.Underlying.SecurityType == SecurityType.Future && symbol.Underlying.IsCanonical()) { AddFuture(symbol.Underlying.ID.Symbol, resolutionToUseForUnderlying); } else if (symbol.Underlying.SecurityType == SecurityType.Future) { AddFutureContract(symbol.Underlying, resolutionToUseForUnderlying); } } var allSymbols = new List <Symbol>(); for (var date = start; date < end; date = date.AddDays(1)) { if (option.Exchange.DateIsOpen(date)) { allSymbols.AddRange(OptionChainProvider.GetOptionContractList(symbol.Underlying, date)); } } var optionFilterUniverse = new OptionFilterUniverse(); var distinctSymbols = allSymbols.Distinct(); symbols = base.History(symbol.Underlying, start, end.Value, resolution) .SelectMany(x => { // the option chain symbols wont change so we can set 'exchangeDateChange' to false always optionFilterUniverse.Refresh(distinctSymbols, x, exchangeDateChange: false); return(option.ContractFilter.Filter(optionFilterUniverse)); }) .Distinct().Concat(new[] { symbol.Underlying }); } else { // the symbol is a contract symbols = new List <Symbol> { symbol }; } return(new OptionHistory(History(symbols, start, end.Value, resolution))); }
/// <summary> /// Liquidate all holdings and cancel open orders. Called at the end of day for tick-strategies. /// </summary> /// <param name="symbolToLiquidate">Symbols we wish to liquidate</param> /// <param name="tag">Custom tag to know who is calling this.</param> /// <returns>Array of order ids for liquidated symbols</returns> /// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/> public List <int> Liquidate(Symbol symbolToLiquidate = null, string tag = "Liquidated") { var orderIdList = new List <int>(); if (!Settings.LiquidateEnabled) { Debug("Liquidate() is currently disabled by settings. To re-enable please set 'Settings.LiquidateEnabled' to true"); return(orderIdList); } IEnumerable <Symbol> toLiquidate; if (symbolToLiquidate != null) { toLiquidate = Securities.ContainsKey(symbolToLiquidate) ? new[] { symbolToLiquidate } : Enumerable.Empty <Symbol>(); } else { toLiquidate = Securities.Keys.OrderBy(x => x.Value); } foreach (var symbol in toLiquidate) { // get open orders var orders = Transactions.GetOpenOrders(symbol); // get quantity in portfolio var quantity = Portfolio[symbol].Quantity; // if there is only one open market order that would close the position, do nothing if (orders.Count == 1 && quantity != 0 && orders[0].Quantity == -quantity && orders[0].Type == OrderType.Market) { continue; } // cancel all open orders var marketOrdersQuantity = 0m; foreach (var order in orders) { if (order.Type == OrderType.Market) { // pending market order var ticket = Transactions.GetOrderTicket(order.Id); if (ticket != null) { // get remaining quantity marketOrdersQuantity += ticket.Quantity - ticket.QuantityFilled; } } else { Transactions.CancelOrder(order.Id, tag); } } // Liquidate at market price if (quantity != 0) { // calculate quantity for closing market order var ticket = Order(symbol, -quantity - marketOrdersQuantity, tag: tag); if (ticket.Status == OrderStatus.Filled) { orderIdList.Add(ticket.OrderId); } } } return(orderIdList); }
/// <summary> /// <see cref = "QuantBook" /> constructor. /// Provides access to data for quantitative analysis /// </summary> public QuantBook() : base() { try { using (Py.GIL()) { _pandas = Py.Import("pandas"); } // Issue #4892 : Set start time relative to NY time // when the data is available from the previous day var newYorkTime = DateTime.UtcNow.ConvertFromUtc(TimeZones.NewYork); var hourThreshold = Config.GetInt("qb-data-hour", 9); // If it is after our hour threshold; then we can use today if (newYorkTime.Hour >= hourThreshold) { SetStartDate(newYorkTime); } else { SetStartDate(newYorkTime - TimeSpan.FromDays(1)); } // Sets PandasConverter SetPandasConverter(); // Reset our composer; needed for re-creation of QuantBook Composer.Instance.Reset(); var composer = Composer.Instance; // Create our handlers with our composer instance var algorithmHandlers = LeanEngineAlgorithmHandlers.FromConfiguration(composer); var systemHandlers = LeanEngineSystemHandlers.FromConfiguration(composer); // init the API systemHandlers.Initialize(); systemHandlers.LeanManager.Initialize(systemHandlers, algorithmHandlers, new BacktestNodePacket(), new AlgorithmManager(false)); systemHandlers.LeanManager.SetAlgorithm(this); algorithmHandlers.DataPermissionsManager.Initialize(new AlgorithmNodePacket(PacketType.BacktestNode) { UserToken = Config.Get("api-access-token"), UserId = Config.GetInt("job-user-id"), ProjectId = Config.GetInt("project-id"), OrganizationId = Config.Get("job-organization-id"), Version = Globals.Version }); algorithmHandlers.ObjectStore.Initialize(Config.Get("research-object-store-name", "QuantBook"), Config.GetInt("job-user-id"), Config.GetInt("project-id"), Config.Get("api-access-token"), new Controls { // if <= 0 we disable periodic persistence and make it synchronous PersistenceIntervalSeconds = -1, StorageLimitMB = Config.GetInt("storage-limit-mb", 5), StorageFileCount = Config.GetInt("storage-file-count", 100), StoragePermissions = (FileAccess)Config.GetInt("storage-permissions", (int)FileAccess.ReadWrite) }); SetObjectStore(algorithmHandlers.ObjectStore); _dataCacheProvider = new ZipDataCacheProvider(algorithmHandlers.DataProvider); _dataProvider = algorithmHandlers.DataProvider; var symbolPropertiesDataBase = SymbolPropertiesDatabase.FromDataFolder(); var registeredTypes = new RegisteredSecurityDataTypesProvider(); var securityService = new SecurityService(Portfolio.CashBook, MarketHoursDatabase, symbolPropertiesDataBase, this, registeredTypes, new SecurityCacheProvider(Portfolio)); Securities.SetSecurityService(securityService); SubscriptionManager.SetDataManager( new DataManager(new NullDataFeed(), new UniverseSelection(this, securityService, algorithmHandlers.DataPermissionsManager, algorithmHandlers.DataProvider), this, TimeKeeper, MarketHoursDatabase, false, registeredTypes, algorithmHandlers.DataPermissionsManager)); var mapFileProvider = algorithmHandlers.MapFileProvider; HistoryProvider = new HistoryProviderManager(); HistoryProvider.Initialize( new HistoryProviderInitializeParameters( null, null, algorithmHandlers.DataProvider, _dataCacheProvider, mapFileProvider, algorithmHandlers.FactorFileProvider, null, true, algorithmHandlers.DataPermissionsManager ) ); SetOptionChainProvider(new CachingOptionChainProvider(new BacktestingOptionChainProvider(_dataCacheProvider, mapFileProvider))); SetFutureChainProvider(new CachingFutureChainProvider(new BacktestingFutureChainProvider(_dataCacheProvider))); } catch (Exception exception) { throw new Exception("QuantBook.Main(): " + exception); } }
public override void OnData(Slice data) { if (!IsWarmingUp && Time.Month != pmonth && VOL_PROTECT) { SetHoldings("VIXM", 0.1m); pmonth = Time.Month; } if (Time.Minute != 0) { return; } foreach (var s in symbols) { if (!Securities.ContainsKey(s)) { continue; } TradeMonitor.RecordPerf(s, Securities[s].Price); if (pvalue[s] > 50 & pfe[s] < 50 || pfe[s] < -50) { if (activate[s]) { jitter++; } activate[s] = false; } else if (pvalue[s] < -50 & pfe[s] > -50 || pfe[s] > 0 && pfe[s] > pvalue[s]) { if (!activate[s]) { jitter++; } activate[s] = true; } pvalue[s] = pfe[s]; if (eit[s].IsReady) { if (Securities.ContainsKey(s) && data.Bars.ContainsKey(s)) { var ratio = 1.0m / MAX_POS; ///(symbols.Contains("VXX.1")) ? 1.0/(symbols.Count()-1) : 1.0 / (symbols.Count()); //if (POS_COUNT >= 10) ratio = 0.1; if (activate[s] && Portfolio[s].Quantity == 0) { if (eit[s] > 0 && data[s].Close > Math.Max(eit[s].Lag, eit[s].InstantaneousTrend)) { BuyRatio(data, s, ratio); } } if (eit[s] < 0 || data[s].Close < Math.Min(eit[s].Lag, eit[s].InstantaneousTrend)) { UpdateReference(s); if (Securities.ContainsKey(s)) { TradeMonitor.CloseAt(s, Securities[s].Price, Time); } if (Portfolio.ContainsKey(s) && Portfolio[s].Quantity != 0 && !IsWarmingUp) { SetHoldings(s, 0); //, tag:TradeMonitor.GetPerfReport(s)); } } else if (!activate[s] && data.Bars.ContainsKey(s) && data.Bars[s].Close < eit[s].Lag) //tightening the grip when trend slowing down according to PFE { UpdateReference(s); TradeMonitor.CloseAt(s, Securities[s].Price, Time); if (Portfolio[s].Quantity != 0 && !IsWarmingUp) { SetHoldings(s, 0); //, tag:TradeMonitor.GetPerfReport(s)); } } //risk mgmt kinda redundant with algo so little impact on DD // else //if (data.Bars.ContainsKey(s)) // { // // if (stopLoss.ContainsKey(s) && data[s].Close < stopLoss[s]) // // { // // UpdateReference(s); // // TradeMonitor.CloseAt(s, Securities[s].Price, Time); // // if (Portfolio[s].Quantity != 0) // // SetHoldings(s, 0, tag:TradeMonitor.GetPerfReport(s)); // // } // // else if (takeProfit.ContainsKey(s) && data[s].Close >= takeProfit[s]) // // { // // if (Portfolio[s].Quantity != 0) // // MarketOrder(s, -0.5m * Portfolio[s].Quantity); // // takeProfit.Remove(s); // // } // // else if (!takeProfit.ContainsKey(s) && data[s].Close < Portfolio[s].AveragePrice) // // { // // UpdateReference(s); // // TradeMonitor.CloseAt(s, Securities[s].Price, Time); // // if (Portfolio[s].Quantity != 0) // // SetHoldings(s, 0, tag:TradeMonitor.GetPerfReport(s)); // // } // } } } } }
/// <summary> /// Perform preorder checks to ensure we have sufficient capital, /// the market is open, and we haven't exceeded maximum realistic orders per day. /// </summary> /// <returns>OrderResponse. If no error, order request is submitted.</returns> private OrderResponse PreOrderChecksImpl(SubmitOrderRequest request) { //Ordering 0 is useless. if (request.Quantity == 0 || request.Symbol == null || request.Symbol == QuantConnect.Symbol.Empty) { return(OrderResponse.ZeroQuantity(request)); } //If we're not tracking this symbol: throw error: if (!Securities.ContainsKey(request.Symbol) && !_sentNoDataError) { _sentNoDataError = true; return(OrderResponse.Error(request, OrderResponseErrorCode.MissingSecurity, "You haven't requested " + request.Symbol.ToString() + " data. Add this with AddSecurity() in the Initialize() Method.")); } //Set a temporary price for validating order for market orders: var security = Securities[request.Symbol]; var price = security.Price; //Check the exchange is open before sending a market on close orders //Allow market orders, they'll just execute when the exchange reopens if (request.OrderType == OrderType.MarketOnClose && !security.Exchange.ExchangeOpen) { return(OrderResponse.Error(request, OrderResponseErrorCode.ExchangeNotOpen, request.OrderType + " order and exchange not open.")); } if (price == 0) { return(OrderResponse.Error(request, OrderResponseErrorCode.SecurityPriceZero, request.Symbol.ToString() + ": asset price is $0. If using custom data make sure you've set the 'Value' property.")); } if (security.Type == SecurityType.Forex) { // for forex pairs we need to verify that the conversions to USD have values as well string baseCurrency, quoteCurrency; Forex.DecomposeCurrencyPair(security.Symbol.Value, out baseCurrency, out quoteCurrency); // verify they're in the portfolio Cash baseCash, quoteCash; if (!Portfolio.CashBook.TryGetValue(baseCurrency, out baseCash) || !Portfolio.CashBook.TryGetValue(quoteCurrency, out quoteCash)) { return(OrderResponse.Error(request, OrderResponseErrorCode.ForexBaseAndQuoteCurrenciesRequired, request.Symbol.Value + ": requires " + baseCurrency + " and " + quoteCurrency + " in the cashbook to trade.")); } // verify we have conversion rates for each leg of the pair back into the account currency if (baseCash.ConversionRate == 0m || quoteCash.ConversionRate == 0m) { return(OrderResponse.Error(request, OrderResponseErrorCode.ForexConversionRateZero, request.Symbol.Value + ": requires " + baseCurrency + " and " + quoteCurrency + " to have non-zero conversion rates. This can be caused by lack of data.")); } } //Make sure the security has some data: if (!security.HasData) { return(OrderResponse.Error(request, OrderResponseErrorCode.SecurityHasNoData, "There is no data for this symbol yet, please check the security.HasData flag to ensure there is at least one data point.")); } //We've already processed too many orders: max 100 per day or the memory usage explodes if (Transactions.OrdersCount > _maxOrders) { Status = AlgorithmStatus.Stopped; return(OrderResponse.Error(request, OrderResponseErrorCode.ExceededMaximumOrders, string.Format("You have exceeded maximum number of orders ({0}), for unlimited orders upgrade your account.", _maxOrders))); } if (request.OrderType == OrderType.MarketOnClose) { // must be submitted with at least 10 minutes in trading day, add buffer allow order submission var latestSubmissionTime = (Time.Date + security.Exchange.MarketClose).AddMinutes(-10.75); if (Time > latestSubmissionTime) { // tell the user we require an 11 minute buffer, on minute data in live a user will receive the 3:49->3:50 bar at 3:50, // this is already too late to submit one of these orders, so make the user do it at the 3:48->3:49 bar so it's submitted // to the brokerage before 3:50. return(OrderResponse.Error(request, OrderResponseErrorCode.MarketOnCloseOrderTooLate, "MarketOnClose orders must be placed with at least a 11 minute buffer before market close.")); } } // passes all initial order checks return(OrderResponse.Success(request)); }
/// <summary> /// Perform preorder checks to ensure we have sufficient capital, /// the market is open, and we haven't exceeded maximum realistic orders per day. /// </summary> /// <returns>OrderResponse. If no error, order request is submitted.</returns> private OrderResponse PreOrderChecksImpl(SubmitOrderRequest request) { //Ordering 0 is useless. if (request.Quantity == 0 || request.Symbol == null || request.Symbol == QuantConnect.Symbol.Empty) { return(OrderResponse.ZeroQuantity(request)); } //If we're not tracking this symbol: throw error: if (!Securities.ContainsKey(request.Symbol) && !_sentNoDataError) { _sentNoDataError = true; return(OrderResponse.Error(request, OrderResponseErrorCode.MissingSecurity, "You haven't requested " + request.Symbol.ToString() + " data. Add this with AddSecurity() in the Initialize() Method.")); } //Set a temporary price for validating order for market orders: var security = Securities[request.Symbol]; if (!security.IsTradable) { return(OrderResponse.Error(request, OrderResponseErrorCode.NonTradableSecurity, "The security with symbol '" + request.Symbol.ToString() + "' is marked as non-tradable.")); } var price = security.Price; //Check the exchange is open before sending a market on close orders if (request.OrderType == OrderType.MarketOnClose && !security.Exchange.ExchangeOpen) { return(OrderResponse.Error(request, OrderResponseErrorCode.ExchangeNotOpen, request.OrderType + " order and exchange not open.")); } if (price == 0) { return(OrderResponse.Error(request, OrderResponseErrorCode.SecurityPriceZero, request.Symbol.ToString() + ": asset price is $0. If using custom data make sure you've set the 'Value' property.")); } // check quote currency existence/conversion rate on all orders Cash quoteCash; var quoteCurrency = security.QuoteCurrency.Symbol; if (!Portfolio.CashBook.TryGetValue(quoteCurrency, out quoteCash)) { return(OrderResponse.Error(request, OrderResponseErrorCode.QuoteCurrencyRequired, request.Symbol.Value + ": requires " + quoteCurrency + " in the cashbook to trade.")); } if (security.QuoteCurrency.ConversionRate == 0m) { return(OrderResponse.Error(request, OrderResponseErrorCode.ConversionRateZero, request.Symbol.Value + ": requires " + quoteCurrency + " to have a non-zero conversion rate. This can be caused by lack of data.")); } // need to also check base currency existence/conversion rate on forex orders if (security.Type == SecurityType.Forex) { Cash baseCash; var baseCurrency = ((Forex)security).BaseCurrencySymbol; if (!Portfolio.CashBook.TryGetValue(baseCurrency, out baseCash)) { return(OrderResponse.Error(request, OrderResponseErrorCode.ForexBaseAndQuoteCurrenciesRequired, request.Symbol.Value + ": requires " + baseCurrency + " and " + quoteCurrency + " in the cashbook to trade.")); } if (baseCash.ConversionRate == 0m) { return(OrderResponse.Error(request, OrderResponseErrorCode.ForexConversionRateZero, request.Symbol.Value + ": requires " + baseCurrency + " and " + quoteCurrency + " to have non-zero conversion rates. This can be caused by lack of data.")); } } //Make sure the security has some data: if (!security.HasData) { return(OrderResponse.Error(request, OrderResponseErrorCode.SecurityHasNoData, "There is no data for this symbol yet, please check the security.HasData flag to ensure there is at least one data point.")); } //We've already processed too many orders: max 100 per day or the memory usage explodes if (Transactions.OrdersCount > _maxOrders) { Status = AlgorithmStatus.Stopped; return(OrderResponse.Error(request, OrderResponseErrorCode.ExceededMaximumOrders, string.Format("You have exceeded maximum number of orders ({0}), for unlimited orders upgrade your account.", _maxOrders))); } if (request.OrderType == OrderType.MarketOnClose) { var nextMarketClose = security.Exchange.Hours.GetNextMarketClose(security.LocalTime, false); // must be submitted with at least 10 minutes in trading day, add buffer allow order submission var latestSubmissionTime = nextMarketClose.AddMinutes(-15.50); if (!security.Exchange.ExchangeOpen || Time > latestSubmissionTime) { // tell the user we require a 16 minute buffer, on minute data in live a user will receive the 3:44->3:45 bar at 3:45, // this is already too late to submit one of these orders, so make the user do it at the 3:43->3:44 bar so it's submitted // to the brokerage before 3:45. return(OrderResponse.Error(request, OrderResponseErrorCode.MarketOnCloseOrderTooLate, "MarketOnClose orders must be placed with at least a 16 minute buffer before market close.")); } } // passes all initial order checks return(OrderResponse.Success(request)); }
public void InitAutoStopLoss() { ASLObject.Load(); comboBoxASLAccount.Click += (s, e) => { if (comboBoxASLAccount.Items.Count == 0) { comboBoxASLAccount.SetListValues(this.Trader.Objects.tClients.ToArray() .Select(c => c.Code).ToArray()); } }; comboBoxASLSec.SetListValues(Global.GetWorkingListSec().ToArray()); comboBoxASLSec.TextChanged += (s, e) => { StopLossSec = null; var text = comboBoxASLSec.Text; if (text.Length >= 2) { var listSec = Trader.Objects.tSecurities.SearchAll(el => el.Code.ToLower().Contains(text.ToLower()) || el.Name.ToLower().Contains(text.ToLower())).Select(el => el.ToString()); if (listSec.Count() > 0) { comboBoxASLSec.Clear(); comboBoxASLSec.SetListValues(listSec); AutoSLUpdateGrid(); } } comboBoxASLSec.Select(text.Length, 0); AutoSLUpdateGrid(); }; comboBoxASLSec.KeyPress += (s, e) => { var k = e.KeyChar; if (e.KeyChar == 13) { if (comboBoxASLSec.Items.Count > 0) { comboBoxASLSec.SelectedItem = comboBoxASLSec.Items[0]; AutoSLUpdatePanel(); AutoSLUpdateGrid(); } } }; comboBoxASLSec.SelectedIndexChanged += (s, e) => { AutoSLUpdatePanel(); }; ASLObject.OnAdd += (condOrder) => { AutoSLUpdateGrid(); }; ASLObject.OnDelete += (condOrder) => { AutoSLUpdateGrid(); }; buttonASLDelete.Click += (s, e) => { if (dataGridViewASLList.SelectedRows.NotIsNull() && dataGridViewASLList.SelectedRows.Count > 0) { foreach (var row in dataGridViewASLList.SelectedRows) { if (row is DataGridViewRow) { var rowEl = (DataGridViewRow)row; if (rowEl.Tag.NotIsNull()) { ASLObject.Delete((AutoStopLoss.Item)rowEl.Tag); } } } } AutoSLUpdateGrid(); }; checkBoxASLBySec.CheckedChanged += (s, e) => { AutoSLUpdateGrid(); }; buttonASLAdd.Click += (s, e) => { AddSLControl(); }; AutoSLUpdateGrid(); }
/// <summary> /// <see cref = "QuantBook" /> constructor. /// Provides access to data for quantitative analysis /// </summary> public QuantBook() : base() { try { using (Py.GIL()) { _pandas = Py.Import("pandas"); } // By default, set start date to end data which is yesterday SetStartDate(EndDate); // Sets PandasConverter SetPandasConverter(); // Initialize History Provider var composer = new Composer(); var algorithmHandlers = LeanEngineAlgorithmHandlers.FromConfiguration(composer); var systemHandlers = LeanEngineSystemHandlers.FromConfiguration(composer); // init the API systemHandlers.Initialize(); systemHandlers.LeanManager.Initialize(systemHandlers, algorithmHandlers, new BacktestNodePacket(), new AlgorithmManager(false)); systemHandlers.LeanManager.SetAlgorithm(this); algorithmHandlers.ObjectStore.Initialize("QuantBook", Config.GetInt("job-user-id"), Config.GetInt("project-id"), Config.Get("api-access-token"), new Controls { // if <= 0 we disable periodic persistence and make it synchronous PersistenceIntervalSeconds = -1 }); SetObjectStore(algorithmHandlers.ObjectStore); _dataCacheProvider = new ZipDataCacheProvider(algorithmHandlers.DataProvider); var symbolPropertiesDataBase = SymbolPropertiesDatabase.FromDataFolder(); var registeredTypes = new RegisteredSecurityDataTypesProvider(); var securityService = new SecurityService(Portfolio.CashBook, MarketHoursDatabase, symbolPropertiesDataBase, this, registeredTypes, new SecurityCacheProvider(Portfolio)); Securities.SetSecurityService(securityService); SubscriptionManager.SetDataManager( new DataManager(new NullDataFeed(), new UniverseSelection(this, securityService), this, TimeKeeper, MarketHoursDatabase, false, registeredTypes)); var mapFileProvider = algorithmHandlers.MapFileProvider; HistoryProvider = composer.GetExportedValueByTypeName <IHistoryProvider>(Config.Get("history-provider", "SubscriptionDataReaderHistoryProvider")); HistoryProvider.Initialize( new HistoryProviderInitializeParameters( null, null, algorithmHandlers.DataProvider, _dataCacheProvider, mapFileProvider, algorithmHandlers.FactorFileProvider, null, true ) ); SetOptionChainProvider(new CachingOptionChainProvider(new BacktestingOptionChainProvider())); SetFutureChainProvider(new CachingFutureChainProvider(new BacktestingFutureChainProvider())); } catch (Exception exception) { throw new Exception("QuantBook.Main(): " + exception); } }
protected override void OnStartExport() { base.OnStartExport(); Securities.ForEach(s => _adapter.SendOutMessage(s.ToMessage(GetSecurityId(s)))); Portfolios.ForEach(p => _adapter.SendOutMessage(p.ToMessage())); }
public override void OnData(Slice data) { // verify expectations if (SubscriptionManager.Subscriptions.Count(x => x.Symbol == OptionChainSymbol) != (_expectUniverseSubscription ? 1 : 0)) { Log($"SubscriptionManager.Subscriptions: {string.Join(" -- ", SubscriptionManager.Subscriptions)}"); throw new Exception($"Unexpected {OptionChainSymbol} subscription presence"); } if (!data.ContainsKey(Underlying)) { // TODO : In fact, we're unable to properly detect whether or not we auto-added or it was manually added // this is because when we auto-add the underlying we don't mark it as an internal security like we do with other auto adds // so there's currently no good way to remove the underlying equity without invoking RemoveSecurity(underlying) manually // from the algorithm, otherwise we may remove it incorrectly. Now, we could track MORE state, but it would likely be a duplication // of the internal flag's purpose, so kicking this issue for now with a big fat note here about it :) to be considerd for any future // refactorings of how we manage subscription/security data and track various aspects about the security (thinking a flags enum with // things like manually added, auto added, internal, and any other boolean state we need to track against a single security) throw new Exception("The underlying equity data should NEVER be removed in this algorithm because it was manually added"); } if (_expectedSecurities.AreDifferent(LinqExtensions.ToHashSet(Securities.Keys))) { var expected = string.Join(Environment.NewLine, _expectedSecurities.OrderBy(s => s.ToString())); var actual = string.Join(Environment.NewLine, Securities.Keys.OrderBy(s => s.ToString())); throw new Exception($"{Time}:: Detected differences in expected and actual securities{Environment.NewLine}Expected:{Environment.NewLine}{expected}{Environment.NewLine}Actual:{Environment.NewLine}{actual}"); } if (_expectedUniverses.AreDifferent(LinqExtensions.ToHashSet(UniverseManager.Keys))) { var expected = string.Join(Environment.NewLine, _expectedUniverses.OrderBy(s => s.ToString())); var actual = string.Join(Environment.NewLine, UniverseManager.Keys.OrderBy(s => s.ToString())); throw new Exception($"{Time}:: Detected differences in expected and actual universes{Environment.NewLine}Expected:{Environment.NewLine}{expected}{Environment.NewLine}Actual:{Environment.NewLine}{actual}"); } if (_expectedData.AreDifferent(LinqExtensions.ToHashSet(data.Keys))) { var expected = string.Join(Environment.NewLine, _expectedData.OrderBy(s => s.ToString())); var actual = string.Join(Environment.NewLine, data.Keys.OrderBy(s => s.ToString())); throw new Exception($"{Time}:: Detected differences in expected and actual slice data keys{Environment.NewLine}Expected:{Environment.NewLine}{expected}{Environment.NewLine}Actual:{Environment.NewLine}{actual}"); } // 10AM add GOOG option chain if (Time.TimeOfDay.Hours == 10 && Time.TimeOfDay.Minutes == 0) { if (Securities.ContainsKey(OptionChainSymbol)) { throw new Exception("The option chain security should not have been added yet"); } var googOptionChain = AddOption(UnderlyingTicker); googOptionChain.SetFilter(u => { // find first put above market price return(u.IncludeWeeklys() .Strikes(+1, +1) .Expiration(TimeSpan.Zero, TimeSpan.FromDays(1)) .Contracts(c => c.Where(s => s.ID.OptionRight == OptionRight.Put))); }); _expectedSecurities.Add(OptionChainSymbol); _expectedUniverses.Add(OptionChainSymbol); _expectUniverseSubscription = true; } // 11:30AM remove GOOG option chain if (Time.TimeOfDay.Hours == 11 && Time.TimeOfDay.Minutes == 30) { RemoveSecurity(OptionChainSymbol); // remove contracts from expected data _expectedData.RemoveWhere(s => _expectedContracts.Contains(s)); // remove option chain universe from expected universes _expectedUniverses.Remove(OptionChainSymbol); // OptionChainSymbol universe subscription should not be present _expectUniverseSubscription = false; } }
/// <summary> Кликеры по таблице стакана </summary> /// <param name="sender"></param> /// <param name="e"></param> private void dataGridViewDepth_Click(object sender, EventArgs e) { if (Securities.IsNull()) { return; } var MouseEvent = (MouseEventArgs)e; var dataGrid = (DataGridView)sender; dataGrid.ClearSelection(); var hti = dataGrid.HitTest(MouseEvent.X, MouseEvent.Y); int indexRow = hti.RowIndex; int indexCol = hti.ColumnIndex; if (indexRow < 0 || indexCol < 0) { return; } DataGridViewCell cell = dataGrid.Rows[indexRow].Cells[indexCol]; if (MouseEvent.Button == MouseButtons.Left) { if (cell.Tag != null) { int Volume = Convert.ToInt32(numericUpDownVolume.Value); if (Volume == 0) { ShowTransReply("Не указан объем!"); } if (cell.Tag.GetType().ToString().Contains("StructClickDepth")) { var data = (StructClickDepth)cell.Tag; OrderDirection?direction = null; if (data.Flag == "buy") { direction = OrderDirection.Buy; } if (data.Flag == "sell") { direction = OrderDirection.Sell; } var clientCode = comboBoxCodeClient.SelectedItem.NotIsNull() ? comboBoxCodeClient.SelectedItem.ToString() : ""; MThread.InitThread(() => { Trader.CreateOrder(new Order() { Sec = Securities, Direction = direction, Price = data.Price, Volume = Volume, ClientCode = clientCode }); }); } } } if (MouseEvent.Button == MouseButtons.Right) { if (cell.Tag != null) { if (cell.Tag.GetType().ToString().Contains("StructClickDepth")) { var data = (StructClickDepth)cell.Tag; if (data.Flag == "buy" || data.Flag == "sell") { MThread.InitThread(() => { var ords = Trader.Objects.tOrders.SearchAll(o => o.Sec == Securities && o.Price == data.Price && o.IsActive()); if (ords.NotIsNull()) { foreach (var ord in ords) { Trader.CancelOrder(ord.Sec, ord.OrderNumber); } } }); } } } } }
/// <summary> /// Create a simple JSON holdings from a Security holding class. /// </summary> /// <param name="holding">Holdings object we'll use to initialize the transport</param> public Holding(Securities.SecurityHolding holding) : this() { Symbol = holding.Symbol; Type = holding.Type; Quantity = holding.Quantity; var rounding = 2; if (holding.Type == SecurityType.Forex) { rounding = 5; string basec, quotec; Forex.DecomposeCurrencyPair(holding.Symbol, out basec, out quotec); CurrencySymbol = Forex.CurrencySymbols[quotec]; ConversionRate = ((ForexHolding) holding).ConversionRate; } AveragePrice = Math.Round(holding.AveragePrice, rounding); MarketPrice = Math.Round(holding.Price, rounding); }
/// <summary> /// Set header /// </summary> /// <param name="securities"></param> private void SetHead(Securities securities) { Text = "(" + securities.Code + ":" + securities.Class.Code + ") " + securities.Name; }