Lean  $LEAN_TAG$
Messages.Securities.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using System.Collections.Generic;
18 using System.Linq;
19 using System.Runtime.CompilerServices;
20 using System.Text;
21 
22 using QuantConnect.Data;
25 
26 using static QuantConnect.StringExtensions;
27 
28 namespace QuantConnect
29 {
30  /// <summary>
31  /// Provides user-facing message construction methods and static messages for the <see cref="Securities"/> namespace
32  /// </summary>
33  public static partial class Messages
34  {
35  /// <summary>
36  /// Provides user-facing messages for the <see cref="Securities.AccountEvent"/> class and its consumers or related classes
37  /// </summary>
38  public static class AccountEvent
39  {
40  [MethodImpl(MethodImplOptions.AggressiveInlining)]
41  public static string ToString(Securities.AccountEvent accountEvent)
42  {
43  return Invariant($"Account {accountEvent.CurrencySymbol} Balance: {accountEvent.CashBalance:0.00}");
44  }
45  }
46 
47  /// <summary>
48  /// Provides user-facing messages for the <see cref="Securities.BuyingPowerModel"/> class and its consumers or related classes
49  /// </summary>
50  public static class BuyingPowerModel
51  {
52  public static string InvalidInitialMarginRequirement = "Initial margin requirement must be between 0 and 1";
53 
54  public static string InvalidMaintenanceMarginRequirement = "Maintenance margin requirement must be between 0 and 1";
55 
56  public static string InvalidFreeBuyingPowerPercentRequirement = "Free Buying Power Percent requirement must be between 0 and 1";
57 
58  public static string InvalidLeverage = "Leverage must be greater than or equal to 1.";
59 
60  [MethodImpl(MethodImplOptions.AggressiveInlining)]
61  public static string InsufficientBuyingPowerDueToNullOrderTicket(Orders.Order order)
62  {
63  return Invariant($"Null order ticket for id: {order.Id}");
64  }
65 
66  [MethodImpl(MethodImplOptions.AggressiveInlining)]
67  public static string InsufficientBuyingPowerDueToUnsufficientMargin(Orders.Order order,
68  decimal initialMarginRequiredForRemainderOfOrder, decimal freeMargin)
69  {
70  return Invariant($@"Id: {order.Id}, Initial Margin: {
71  initialMarginRequiredForRemainderOfOrder.Normalize()}, Free Margin: {freeMargin.Normalize()}");
72  }
73 
74  [MethodImpl(MethodImplOptions.AggressiveInlining)]
75  public static string TargetOrderMarginNotAboveMinimum(decimal absDifferenceOfMargin, decimal minimumValue)
76  {
77  return Invariant($"The target order margin {absDifferenceOfMargin} is less than the minimum {minimumValue}.");
78  }
79 
80  [MethodImpl(MethodImplOptions.AggressiveInlining)]
81  public static string TargetOrderMarginNotAboveMinimum()
82  {
83  return "Warning: Portfolio rebalance result ignored as it resulted in a single share trade recommendation which can generate high fees." +
84  " To disable minimum order size checks please set Settings.MinimumOrderMarginPortfolioPercentage = 0.";
85  }
86 
87  [MethodImpl(MethodImplOptions.AggressiveInlining)]
88  public static string OrderQuantityLessThanLotSize(Securities.Security security, decimal targetOrderMargin)
89  {
90  return Invariant($@"The order quantity is less than the lot size of {
91  security.SymbolProperties.LotSize} and has been rounded to zero. Target order margin {targetOrderMargin}. ");
92  }
93 
94  [MethodImpl(MethodImplOptions.AggressiveInlining)]
95  public static string FailedToConvergeOnTheTargetMargin(GetMaximumOrderQuantityForTargetBuyingPowerParameters parameters,
96  decimal signedTargetFinalMarginValue, decimal orderFees)
97  {
98  return Invariant($@"GetMaximumOrderQuantityForTargetBuyingPower failed to converge on the target margin: {
99  signedTargetFinalMarginValue}; the following information can be used to reproduce the issue. Total Portfolio Cash: {
100  parameters.Portfolio.Cash}; Security : {parameters.Security.Symbol.ID}; Price : {parameters.Security.Close}; Leverage: {
101  parameters.Security.Leverage}; Order Fee: {orderFees}; Lot Size: {
102  parameters.Security.SymbolProperties.LotSize}; Current Holdings: {parameters.Security.Holdings.Quantity} @ {
103  parameters.Security.Holdings.AveragePrice}; Target Percentage: %{parameters.TargetBuyingPower * 100};");
104  }
105 
106  [MethodImpl(MethodImplOptions.AggressiveInlining)]
107  public static string FailedToConvergeOnTheTargetMarginUnderlyingSecurityInfo(Securities.Security underlying)
108  {
109  return Invariant($@"Underlying Security: {underlying.Symbol.ID}; Underlying Price: {
110  underlying.Close}; Underlying Holdings: {underlying.Holdings.Quantity} @ {underlying.Holdings.AveragePrice};");
111  }
112 
113  [MethodImpl(MethodImplOptions.AggressiveInlining)]
114  public static string MarginBeingAdjustedInTheWrongDirection(decimal targetMargin, decimal marginForOneUnit, Securities.Security security)
115  {
116  return Invariant(
117  $@"Margin is being adjusted in the wrong direction. Reproduce this issue with the following variables, Target Margin: {
118  targetMargin}; MarginForOneUnit: {marginForOneUnit}; Security Holdings: {security.Holdings.Quantity} @ {
119  security.Holdings.AveragePrice}; LotSize: {security.SymbolProperties.LotSize}; Price: {security.Close}; Leverage: {
120  security.Leverage}");
121  }
122 
123  [MethodImpl(MethodImplOptions.AggressiveInlining)]
124  public static string MarginBeingAdjustedInTheWrongDirectionUnderlyingSecurityInfo(Securities.Security underlying)
125  {
126  return Invariant($@"Underlying Security: {underlying.Symbol.ID}; Underlying Price: {
127  underlying.Close}; Underlying Holdings: {underlying.Holdings.Quantity} @ {underlying.Holdings.AveragePrice};");
128  }
129  }
130 
131  /// <summary>
132  /// Provides user-facing messages for the <see cref="Securities.PositionGroupBuyingPowerModel"/> class and its consumers or related classes
133  /// </summary>
134  public static class PositionGroupBuyingPowerModel
135  {
136 
137  public static string DeltaCannotBeApplied = "No buying power used, delta cannot be applied";
138 
139  [MethodImpl(MethodImplOptions.AggressiveInlining)]
140  public static string ComputedZeroInitialMargin(IPositionGroup positionGroup)
141  {
142  return Invariant($"Computed zero initial margin requirement for {positionGroup.GetUserFriendlyName()}.");
143  }
144 
145  [MethodImpl(MethodImplOptions.AggressiveInlining)]
146  public static string PositionGroupQuantityRoundedToZero(decimal targetOrderMargin)
147  {
148  return Invariant($"The position group order quantity has been rounded to zero. Target order margin {targetOrderMargin}.");
149  }
150 
151  [MethodImpl(MethodImplOptions.AggressiveInlining)]
152  public static string FailedToConvergeOnTargetMargin(decimal targetMargin, decimal positionGroupQuantity, decimal orderFees,
154  {
155  return Invariant($@"Failed to converge on the target margin: {targetMargin}; the following information can be used to reproduce the issue. Total Portfolio Cash: {parameters.Portfolio.Cash}; Position group: {parameters.PositionGroup.GetUserFriendlyName()}; Position group order quantity: {positionGroupQuantity} Order Fee: {orderFees}; Current Holdings: {parameters.PositionGroup.Quantity}; Target Percentage: %{parameters.TargetBuyingPower * 100};");
156  }
157  }
158 
159  /// <summary>
160  /// Provides user-facing messages for the <see cref="Securities.Cash"/> class and its consumers or related classes
161  /// </summary>
162  public static class Cash
163  {
164  public static string NullOrEmptyCashSymbol = "Cash symbols cannot be null or empty.";
165 
166  [MethodImpl(MethodImplOptions.AggressiveInlining)]
167  public static string NoTradablePairFoundForCurrencyConversion(string cashCurrencySymbol, string accountCurrency,
168  IEnumerable<KeyValuePair<SecurityType, string>> marketMap)
169  {
170  return Invariant($@"No tradeable pair was found for currency {cashCurrencySymbol}, conversion rate to account currency ({
171  accountCurrency}) will be set to zero. Markets: [{string.Join(",", marketMap.Select(x => $"{x.Key}:{x.Value}"))}]");
172  }
173 
174  [MethodImpl(MethodImplOptions.AggressiveInlining)]
175  public static string AddingSecuritySymbolForCashCurrencyFeed(QuantConnect.Symbol symbol, string cashCurrencySymbol)
176  {
177  return Invariant($"Adding {symbol.Value} {symbol.ID.Market} for cash {cashCurrencySymbol} currency feed");
178  }
179 
180  [MethodImpl(MethodImplOptions.AggressiveInlining)]
181  public static string ToString(Securities.Cash cash, string accountCurrency)
182  {
183  // round the conversion rate for output
184  var rate = cash.ConversionRate;
185  rate = rate < 1000 ? rate.RoundToSignificantDigits(5) : Math.Round(rate, 2);
186  return Invariant($@"{cash.Symbol}: {cash.CurrencySymbol}{cash.Amount,15:0.00} @ {rate,10:0.00####} = {
187  QuantConnect.Currencies.GetCurrencySymbol(accountCurrency)}{Math.Round(cash.ValueInAccountCurrency, 2)}");
188  }
189  }
190 
191  /// <summary>
192  /// Provides user-facing messages for the <see cref="Securities.CashBook"/> class and its consumers or related classes
193  /// </summary>
194  public static class CashBook
195  {
196  public static string UnexpectedRequestForNullCurrency = "Unexpected request for NullCurrency Cash instance";
197 
198  [MethodImpl(MethodImplOptions.AggressiveInlining)]
199  public static string ConversionRateNotFound(string currency)
200  {
201  return Invariant($"The conversion rate for {currency} is not available.");
202  }
203 
204  [MethodImpl(MethodImplOptions.AggressiveInlining)]
205  public static string ToString(Securities.CashBook cashBook)
206  {
207  var sb = new StringBuilder();
208  sb.AppendLine(Invariant($"Symbol {"Quantity",13} {"Conversion",10} = Value in {cashBook.AccountCurrency}"));
209  foreach (var value in cashBook.Values)
210  {
211  sb.AppendLine(value.ToString(cashBook.AccountCurrency));
212  }
213  sb.AppendLine("-------------------------------------------------");
214  sb.AppendLine(Invariant($@"CashBook Total Value: {
215  QuantConnect.Currencies.GetCurrencySymbol(cashBook.AccountCurrency)}{
216  Math.Round(cashBook.TotalValueInAccountCurrency, 2).ToStringInvariant()}"));
217 
218  return sb.ToString();
219  }
220 
221  [MethodImpl(MethodImplOptions.AggressiveInlining)]
222  public static string CashSymbolNotFound(string symbol)
223  {
224  return $"This cash symbol ({symbol}) was not found in your cash book.";
225  }
226 
227  [MethodImpl(MethodImplOptions.AggressiveInlining)]
228  public static string FailedToRemoveRecord(string symbol)
229  {
230  return $"Failed to remove the cash book record for symbol {symbol}";
231  }
232  }
233 
234  /// <summary>
235  /// Provides user-facing messages for the <see cref="Securities.CashBuyingPowerModel"/> class and its consumers or related classes
236  /// </summary>
237  public static class CashBuyingPowerModel
238  {
239  public static string UnsupportedLeverage = "CashBuyingPowerModel does not allow setting leverage. Cash accounts have no leverage.";
240 
241  public static string GetMaximumOrderQuantityForDeltaBuyingPowerNotImplemented =
242  $@"The {nameof(CashBuyingPowerModel)} does not require '{
243  nameof(Securities.CashBuyingPowerModel.GetMaximumOrderQuantityForDeltaBuyingPower)}'.";
244 
245  public static string ShortingNotSupported = "The cash model does not allow shorting.";
246 
247  public static string InvalidSecurity = $"The security type must be {nameof(SecurityType.Crypto)}or {nameof(SecurityType.Forex)}.";
248 
249  [MethodImpl(MethodImplOptions.AggressiveInlining)]
250  public static string UnsupportedSecurity(Securities.Security security)
251  {
252  return $@"The '{security.Symbol.Value}' security is not supported by this cash model. Currently only {
253  nameof(SecurityType.Crypto)} and {nameof(SecurityType.Forex)} are supported.";
254  }
255 
256  [MethodImpl(MethodImplOptions.AggressiveInlining)]
257  public static string SellOrderShortHoldingsNotSupported(decimal totalQuantity, decimal openOrdersReservedQuantity, decimal orderQuantity,
258  IBaseCurrencySymbol baseCurrency)
259  {
260  return Invariant($@"Your portfolio holds {totalQuantity.Normalize()} {
261  baseCurrency.BaseCurrency.Symbol}, {openOrdersReservedQuantity.Normalize()} {
262  baseCurrency.BaseCurrency.Symbol} of which are reserved for open orders, but your Sell order is for {
263  orderQuantity.Normalize()} {baseCurrency.BaseCurrency.Symbol
264  }. Cash Modeling trading does not permit short holdings so ensure you only sell what you have, including any additional open orders.");
265  }
266 
267  [MethodImpl(MethodImplOptions.AggressiveInlining)]
268  public static string BuyOrderQuantityGreaterThanMaxForBuyingPower(decimal totalQuantity, decimal maximumQuantity,
269  decimal openOrdersReservedQuantity, decimal orderQuantity, IBaseCurrencySymbol baseCurrency, Securities.Security security,
270  Orders.Order order)
271  {
272  return Invariant($@"Your portfolio holds {totalQuantity.Normalize()} {
273  security.QuoteCurrency.Symbol}, {openOrdersReservedQuantity.Normalize()} {
274  security.QuoteCurrency.Symbol} of which are reserved for open orders, but your Buy order is for {
275  order.AbsoluteQuantity.Normalize()} {baseCurrency.BaseCurrency.Symbol}. Your order requires a total value of {
276  orderQuantity.Normalize()} {security.QuoteCurrency.Symbol}, but only a total value of {
277  Math.Abs(maximumQuantity).Normalize()} {security.QuoteCurrency.Symbol} is available.");
278  }
279 
280  [MethodImpl(MethodImplOptions.AggressiveInlining)]
281  public static string NoDataInInternalCashFeedYet(Securities.Security security, Securities.SecurityPortfolioManager portfolio)
282  {
283  return Invariant($@"The internal cash feed required for converting {security.QuoteCurrency.Symbol} to {
284  portfolio.CashBook.AccountCurrency} does not have any data yet (or market may be closed).");
285  }
286 
287  [MethodImpl(MethodImplOptions.AggressiveInlining)]
288  public static string ZeroContractMultiplier(Securities.Security security)
289  {
290  return $@"The contract multiplier for the {
291  security.Symbol.Value} security is zero. The symbol properties database may be out of date.";
292  }
293 
294  [MethodImpl(MethodImplOptions.AggressiveInlining)]
295  public static string OrderQuantityLessThanLotSize(Securities.Security security)
296  {
297  return Invariant($@"The order quantity is less than the lot size of {
298  security.SymbolProperties.LotSize} and has been rounded to zero.");
299  }
300 
301  [MethodImpl(MethodImplOptions.AggressiveInlining)]
302  public static string OrderQuantityLessThanLotSizeOrderDetails(decimal targetOrderValue, decimal orderQuantity, decimal orderFees)
303  {
304  return Invariant($"Target order value {targetOrderValue}. Order fees {orderFees}. Order quantity {orderQuantity}.");
305  }
306 
307  [MethodImpl(MethodImplOptions.AggressiveInlining)]
308  public static string FailedToConvergeOnTargetOrderValue(decimal targetOrderValue, decimal currentOrderValue, decimal orderQuantity,
309  decimal orderFees, Securities.Security security)
310  {
311  return Invariant($@"GetMaximumOrderQuantityForTargetBuyingPower failed to converge to target order value {
312  targetOrderValue}. Current order value is {currentOrderValue}. Order quantity {orderQuantity}. Lot size is {
313  security.SymbolProperties.LotSize}. Order fees {orderFees}. Security symbol {security.Symbol}");
314  }
315  }
316 
317  /// <summary>
318  /// Provides user-facing messages for the <see cref="Securities.DefaultMarginCallModel"/> class and its consumers or related classes
319  /// </summary>
320  public static class DefaultMarginCallModel
321  {
322  public static string MarginCallOrderTag = "Margin Call";
323  }
324 
325  /// <summary>
326  /// Provides user-facing messages for the <see cref="Securities.DynamicSecurityData"/> class and its consumers or related classes
327  /// </summary>
328  public static class DynamicSecurityData
329  {
330  public static string PropertiesCannotBeSet =
331  "DynamicSecurityData is a view of the SecurityCache. It is readonly, properties can not be set";
332 
333  [MethodImpl(MethodImplOptions.AggressiveInlining)]
334  public static string PropertyNotFound(string name)
335  {
336  return $"Property with name '{name}' does not exist.";
337  }
338 
339  [MethodImpl(MethodImplOptions.AggressiveInlining)]
340  public static string UnexpectedTypesForGetAll(Type type, object data)
341  {
342  return $"Expected a list with type '{type.GetBetterTypeName()}' but found type '{data.GetType().GetBetterTypeName()}";
343  }
344  }
345 
346  /// <summary>
347  /// Provides user-facing messages for the <see cref="Securities.EquityPriceVariationModel"/> class and its consumers or related classes
348  /// </summary>
349  public static class EquityPriceVariationModel
350  {
351  [MethodImpl(MethodImplOptions.AggressiveInlining)]
352  public static string InvalidSecurityType(Securities.Security security)
353  {
354  return Invariant($"Invalid SecurityType: {security.Type}");
355  }
356  }
357 
358  /// <summary>
359  /// Provides user-facing messages for the <see cref="Securities.ErrorCurrencyConverter"/> class and its consumers or related classes
360  /// </summary>
361  public static class ErrorCurrencyConverter
362  {
363  public static string AccountCurrencyUnexpectedUsage = "Unexpected usage of ErrorCurrencyConverter.AccountCurrency";
364 
365  public static string ConvertToAccountCurrencyPurposefullyThrow =
366  $@"This method purposefully throws as a proof that a test does not depend on {
367  nameof(ICurrencyConverter)}. If this exception is encountered, it means the test DOES depend on {
368  nameof(ICurrencyConverter)} and should be properly updated to use a real implementation of {nameof(ICurrencyConverter)}.";
369  }
370 
371  /// <summary>
372  /// Provides user-facing messages for the <see cref="Securities.FuncSecuritySeeder"/> class and its consumers or related classes
373  /// </summary>
374  public static class FuncSecuritySeeder
375  {
376  [MethodImpl(MethodImplOptions.AggressiveInlining)]
377  public static string SeededSecurityInfo(BaseData seedData)
378  {
379  return $"Seeded security: {seedData.Symbol.Value}: {seedData.GetType()} {seedData.Value}";
380  }
381 
382  [MethodImpl(MethodImplOptions.AggressiveInlining)]
383  public static string UnableToSeedSecurity(Securities.Security security)
384  {
385  return $"Unable to seed security: {security.Symbol.Value}";
386  }
387 
388  [MethodImpl(MethodImplOptions.AggressiveInlining)]
389  public static string UnableToSecurityPrice(Securities.Security security)
390  {
391  return $"Could not seed price for security {security.Symbol}";
392  }
393  }
394 
395  /// <summary>
396  /// Provides user-facing messages for the <see cref="Securities.IdentityCurrencyConverter"/> class and its consumers or related classes
397  /// </summary>
398  public static class IdentityCurrencyConverter
399  {
400  public static string UnableToHandleCashInNonAccountCurrency =
401  $"The {nameof(Securities.IdentityCurrencyConverter)} can only handle CashAmounts in units of the account currency";
402  }
403 
404  /// <summary>
405  /// Provides user-facing messages for the <see cref="Securities.InitialMarginParameters"/> class and its consumers or related classes
406  /// </summary>
407  public static class InitialMarginParameters
408  {
409  public static string ForUnderlyingOnlyInvokableForIDerivativeSecurity =
410  "ForUnderlying is only invokable for IDerivativeSecurity (Option|Future)";
411  }
412 
413  /// <summary>
414  /// Provides user-facing messages for the <see cref="Securities.LocalMarketHours"/> class and its consumers or related classes
415  /// </summary>
416  public static class LocalMarketHours
417  {
418  [MethodImpl(MethodImplOptions.AggressiveInlining)]
419  public static string ToString(Securities.LocalMarketHours instance)
420  {
421  if (instance.IsClosedAllDay)
422  {
423  return "Closed All Day";
424  }
425 
426  if (instance.IsOpenAllDay)
427  {
428  return "Open All Day";
429  }
430 
431  return Invariant($"{instance.DayOfWeek}: {string.Join(" | ", instance.Segments)}");
432  }
433  }
434 
435  /// <summary>
436  /// Provides user-facing messages for the <see cref="Securities.MaintenanceMarginParameters"/> class and its consumers or related classes
437  /// </summary>
438  public static class MaintenanceMarginParameters
439  {
440  public static string ForUnderlyingOnlyInvokableForIDerivativeSecurity =
441  "ForUnderlying is only invokable for IDerivativeSecurity (Option|Future)";
442  }
443 
444  /// <summary>
445  /// Provides user-facing messages for the <see cref="Securities.MarketHoursDatabase"/> class and its consumers or related classes
446  /// </summary>
447  public static class MarketHoursDatabase
448  {
449  public static string FutureUsaMarketTypeNoLongerSupported =
450  "Future.Usa market type is no longer supported as we mapped each ticker to its actual exchange. " +
451  "Please find your specific market in the symbol-properties database.";
452 
453  [MethodImpl(MethodImplOptions.AggressiveInlining)]
454  public static string ExchangeHoursNotFound(Securities.SecurityDatabaseKey key,
455  IEnumerable<Securities.SecurityDatabaseKey> availableKeys = null)
456  {
457  var keys = "";
458  if (availableKeys != null)
459  {
460  keys = " Available keys: " + string.Join(", ", availableKeys);
461  }
462 
463  return $"Unable to locate exchange hours for {key}.{keys}";
464  }
465 
466  [MethodImpl(MethodImplOptions.AggressiveInlining)]
467  public static string SuggestedMarketBasedOnTicker(string market)
468  {
469  return $"Suggested market based on the provided ticker 'Market.{market.ToUpperInvariant()}'.";
470  }
471  }
472 
473  /// <summary>
474  /// Provides user-facing messages for the <see cref="Securities.MarketHoursSegment"/> class and its consumers or related classes
475  /// </summary>
476  public static class MarketHoursSegment
477  {
478  public static string InvalidExtendedMarketOpenTime = "Extended market open time must be less than or equal to market open time.";
479 
480  public static string InvalidMarketCloseTime = "Market close time must be after market open time.";
481 
482  public static string InvalidExtendedMarketCloseTime = "Extended market close time must be greater than or equal to market close time.";
483 
484  [MethodImpl(MethodImplOptions.AggressiveInlining)]
485  public static string ToString(Securities.MarketHoursSegment instance)
486  {
487  return $"{instance.State}: {instance.Start.ToStringInvariant(null)}-{instance.End.ToStringInvariant(null)}";
488  }
489  }
490 
491  /// <summary>
492  /// Provides user-facing messages for the <see cref="Securities.RegisteredSecurityDataTypesProvider"/> class and its consumers or related classes
493  /// </summary>
495  {
496  [MethodImpl(MethodImplOptions.AggressiveInlining)]
497  public static string TwoDifferentTypesDetectedForTheSameTypeName(Type type, Type existingType)
498  {
499  return $"Two different types were detected trying to register the same type name: {existingType} - {type}";
500  }
501  }
502 
503  /// <summary>
504  /// Provides user-facing messages for the <see cref="Securities.Security"/> class and its consumers or related classes
505  /// </summary>
506  public static class Security
507  {
508  public static string ValidSymbolPropertiesInstanceRequired = "Security requires a valid SymbolProperties instance.";
509 
510  public static string UnmatchingQuoteCurrencies = "symbolProperties.QuoteCurrency must match the quoteCurrency.Symbol";
511 
512  public static string SetLocalTimeKeeperMustBeCalledBeforeUsingLocalTime =
513  "Security.SetLocalTimeKeeper(LocalTimeKeeper) must be called in order to use the LocalTime property.";
514 
515  public static string UnmatchingSymbols = "Symbols must match.";
516 
517  public static string UnmatchingExchangeTimeZones = "ExchangeTimeZones must match.";
518  }
519 
520  /// <summary>
521  /// Provides user-facing messages for the <see cref="Securities.SecurityDatabaseKey"/> class and its consumers or related classes
522  /// </summary>
523  public static class SecurityDatabaseKey
524  {
525  [MethodImpl(MethodImplOptions.AggressiveInlining)]
526  public static string KeyNotInExpectedFormat(string key)
527  {
528  return $"The specified key was not in the expected format: {key}";
529  }
530 
531  [MethodImpl(MethodImplOptions.AggressiveInlining)]
532  public static string ToString(Securities.SecurityDatabaseKey instance)
533  {
534  return Invariant($"{instance.SecurityType}-{instance.Market}-{instance.Symbol}");
535  }
536  }
537 
538  /// <summary>
539  /// Provides user-facing messages for the <see cref="Securities.SecurityDefinitionSymbolResolver"/> class and its consumers or related classes
540  /// </summary>
542  {
543  [MethodImpl(MethodImplOptions.AggressiveInlining)]
544  public static string NoSecurityDefinitionsLoaded(string securitiesDefinitionKey)
545  {
546  return $"No security definitions data loaded from file: {securitiesDefinitionKey}";
547  }
548  }
549 
550  /// <summary>
551  /// Provides user-facing messages for the <see cref="Securities.SecurityExchangeHours"/> class and its consumers or related classes
552  /// </summary>
553  public static class SecurityExchangeHours
554  {
555  public static string UnableToLocateNextMarketOpenInTwoWeeks = "Unable to locate next market open within two weeks.";
556 
557  public static string UnableToLocateNextMarketCloseInTwoWeeks = "Unable to locate next market close within two weeks.";
558 
559  [MethodImpl(MethodImplOptions.AggressiveInlining)]
560  public static string LastMarketOpenNotFound(DateTime localDateTime, bool isMarketAlwaysOpen)
561  {
562  return $"Did not find last market open for {localDateTime}. IsMarketAlwaysOpen: {isMarketAlwaysOpen}";
563  }
564  }
565 
566  /// <summary>
567  /// Provides user-facing messages for the <see cref="Securities.SecurityHolding"/> class and its consumers or related classes
568  /// </summary>
569  public static class SecurityHolding
570  {
571  [MethodImpl(MethodImplOptions.AggressiveInlining)]
572  public static string ToString(Securities.SecurityHolding instance)
573  {
574  return Invariant($"{instance.Symbol.Value}: {instance.Quantity} @ {instance.AveragePrice}");
575  }
576  }
577 
578  /// <summary>
579  /// Provides user-facing messages for the <see cref="Securities.SecurityManager"/> class and its consumers or related classes
580  /// </summary>
581  public static class SecurityManager
582  {
583  [MethodImpl(MethodImplOptions.AggressiveInlining)]
584  public static string SymbolNotFoundInSecurities(QuantConnect.Symbol symbol)
585  {
586  return Invariant($@"This asset symbol ({
587  symbol}) was not found in your security list. Please add this security or check it exists before using it with 'Securities.ContainsKey(""{
588  QuantConnect.SymbolCache.GetTicker(symbol)}"")'");
589  }
590 
591  [MethodImpl(MethodImplOptions.AggressiveInlining)]
592  public static string UnableToOverwriteSecurity(QuantConnect.Symbol symbol)
593  {
594  return Invariant($"Unable to overwrite existing Security: {symbol}");
595  }
596  }
597 
598  /// <summary>
599  /// Provides user-facing messages for the <see cref="Securities.SecurityPortfolioManager"/> class and its consumers or related classes
600  /// </summary>
601  public static class SecurityPortfolioManager
602  {
603  public static string DictionaryAddNotImplemented =
604  "Portfolio object is an adaptor for Security Manager. To add a new asset add the required data during initialization.";
605 
606  public static string DictionaryClearNotImplemented = "Portfolio object is an adaptor for Security Manager and cannot be cleared.";
607 
608  public static string DictionaryRemoveNotImplemented = "Portfolio object is an adaptor for Security Manager and objects cannot be removed.";
609 
610  public static string CannotChangeAccountCurrencyAfterAddingSecurity =
611  "Cannot change AccountCurrency after adding a Security. Please move SetAccountCurrency() before AddSecurity().";
612 
613  public static string CannotChangeAccountCurrencyAfterSettingCash =
614  "Cannot change AccountCurrency after setting cash. Please move SetAccountCurrency() before SetCash().";
615 
616  [MethodImpl(MethodImplOptions.AggressiveInlining)]
617  public static string AccountCurrencyAlreadySet(Securities.CashBook cashBook, string newAccountCurrency)
618  {
619  return $"account currency has already been set to {cashBook.AccountCurrency}. Will ignore new value {newAccountCurrency}";
620  }
621 
622  [MethodImpl(MethodImplOptions.AggressiveInlining)]
623  public static string SettingAccountCurrency(string accountCurrency)
624  {
625  return $"setting account currency to {accountCurrency}";
626  }
627 
628  [MethodImpl(MethodImplOptions.AggressiveInlining)]
629  public static string TotalMarginInformation(decimal totalMarginUsed, decimal marginRemaining)
630  {
631  return Invariant($"Total margin information: TotalMarginUsed: {totalMarginUsed:F2}, MarginRemaining: {marginRemaining:F2}");
632  }
633 
634  [MethodImpl(MethodImplOptions.AggressiveInlining)]
635  public static string OrderRequestMarginInformation(decimal marginUsed, decimal marginRemaining)
636  {
637  return Invariant($"Order request margin information: MarginUsed: {marginUsed:F2}, MarginRemaining: {marginRemaining:F2}");
638  }
639  }
640 
641  /// <summary>
642  /// Provides user-facing messages for the <see cref="Securities.SecurityService"/> class and its consumers or related classes
643  /// </summary>
644  public static class SecurityService
645  {
646  [MethodImpl(MethodImplOptions.AggressiveInlining)]
647  public static string SymbolNotFoundInSymbolPropertiesDatabase(QuantConnect.Symbol symbol)
648  {
649  return $"Symbol can't be found in the Symbol Properties Database: {symbol.Value}";
650  }
651  }
652 
653  /// <summary>
654  /// Provides user-facing messages for the <see cref="Securities.SecurityTransactionManager"/> class and its consumers or related classes
655  /// </summary>
656  public static class SecurityTransactionManager
657  {
658  public static string CancelOpenOrdersNotAllowedOnInitializeOrWarmUp =
659  "This operation is not allowed in Initialize or during warm up: CancelOpenOrders. Please move this code to the OnWarmupFinished() method.";
660 
661  [MethodImpl(MethodImplOptions.AggressiveInlining)]
662  public static string OrderCanceledByCancelOpenOrders(DateTime time)
663  {
664  return Invariant($"Canceled by CancelOpenOrders() at {time:o}");
665  }
666 
667  [MethodImpl(MethodImplOptions.AggressiveInlining)]
668  public static string UnableToLocateOrderTicket(int orderId)
669  {
670  return Invariant($"Unable to locate ticket for order: {orderId}");
671  }
672 
673  [MethodImpl(MethodImplOptions.AggressiveInlining)]
674  public static string OrderNotFilledWithinExpectedTime(TimeSpan fillTimeout)
675  {
676  return Invariant($"Order did not fill within {fillTimeout.TotalSeconds} seconds.");
677  }
678  }
679 
680  /// <summary>
681  /// Provides user-facing messages for the <see cref="Securities.SymbolProperties"/> class and its consumers or related classes
682  /// </summary>
683  public static class SymbolProperties
684  {
685  public static string InvalidLotSize = "SymbolProperties LotSize can not be less than or equal to 0";
686 
687  public static string InvalidPriceMagnifier = "SymbolProprties PriceMagnifier can not be less than or equal to 0";
688 
689  public static string InvalidStrikeMultiplier = "SymbolProperties StrikeMultiplier can not be less than or equal to 0";
690 
691  [MethodImpl(MethodImplOptions.AggressiveInlining)]
692  public static string ToString(Securities.SymbolProperties instance)
693  {
694  var marketTicker = ",";
695  var minimumOrderSize = marketTicker;
696  var priceMagnifier = marketTicker;
697  if (!string.IsNullOrEmpty(instance.MarketTicker))
698  {
699  marketTicker = $",{instance.MarketTicker}";
700  }
701  if (instance.MinimumOrderSize != null)
702  {
703  minimumOrderSize = Invariant($",{instance.MinimumOrderSize}");
704  }
705  if (instance.PriceMagnifier != 1)
706  {
707  priceMagnifier = Invariant($",{instance.PriceMagnifier}");
708  }
709 
710  return Invariant($@"{instance.Description},{instance.QuoteCurrency},{instance.ContractMultiplier},{
711  instance.MinimumPriceVariation},{instance.LotSize}{marketTicker}{minimumOrderSize}{priceMagnifier}");
712  }
713  }
714 
715  /// <summary>
716  /// Provides user-facing messages for the <see cref="Securities.SymbolPropertiesDatabase"/> class and its consumers or related classes
717  /// </summary>
718  public static class SymbolPropertiesDatabase
719  {
720  //public static string InvalidLotSize = "SymbolProperties LotSize can not be less than or equal to 0";
721 
722  [MethodImpl(MethodImplOptions.AggressiveInlining)]
723  public static string DuplicateKeyInFile(string file, Securities.SecurityDatabaseKey key)
724  {
725  return $"Encountered duplicate key while processing file: {file}. Key: {key}";
726  }
727 
728  [MethodImpl(MethodImplOptions.AggressiveInlining)]
729  public static string DatabaseFileNotFound(string file)
730  {
731  return $"Unable to locate symbol properties file: {file}";
732  }
733  }
734  }
735 }