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  /// <summary>
41  /// Returns a string message containing basic information about the given accountEvent
42  /// </summary>
43  [MethodImpl(MethodImplOptions.AggressiveInlining)]
44  public static string ToString(Securities.AccountEvent accountEvent)
45  {
46  return Invariant($"Account {accountEvent.CurrencySymbol} Balance: {accountEvent.CashBalance:0.00}");
47  }
48  }
49 
50  /// <summary>
51  /// Provides user-facing messages for the <see cref="Securities.BuyingPowerModel"/> class and its consumers or related classes
52  /// </summary>
53  public static class BuyingPowerModel
54  {
55  /// <summary>
56  /// String message saying: Initial margin requirement must be between 0 and 1
57  /// </summary>
58  public static string InvalidInitialMarginRequirement = "Initial margin requirement must be between 0 and 1";
59 
60  /// <summary>
61  /// String messsage saying: Maintenance margin requirement must be between 0 and 1
62  /// </summary>
63  public static string InvalidMaintenanceMarginRequirement = "Maintenance margin requirement must be between 0 and 1";
64 
65  /// <summary>
66  /// String message saying: Free Buying Power Percent requirement must be between 0 and 1
67  /// </summary>
68  public static string InvalidFreeBuyingPowerPercentRequirement = "Free Buying Power Percent requirement must be between 0 and 1";
69 
70  /// <summary>
71  /// String message saying: Leverage must be greater than or equal to 1
72  /// </summary>
73  public static string InvalidLeverage = "Leverage must be greater than or equal to 1.";
74 
75  /// <summary>
76  /// Returns a string message saying the order associated with the id of the given order is null
77  /// </summary>
78  [MethodImpl(MethodImplOptions.AggressiveInlining)]
79  public static string InsufficientBuyingPowerDueToNullOrderTicket(Orders.Order order)
80  {
81  return Invariant($"Null order ticket for id: {order.Id}");
82  }
83 
84  /// <summary>
85  /// Returns a string mesage containing information about the order ID, the initial margin and
86  /// the free margin
87  /// </summary>
88  [MethodImpl(MethodImplOptions.AggressiveInlining)]
89  public static string InsufficientBuyingPowerDueToUnsufficientMargin(Orders.Order order,
90  decimal initialMarginRequiredForRemainderOfOrder, decimal freeMargin)
91  {
92  return Invariant($@"Id: {order.Id}, Initial Margin: {
93  initialMarginRequiredForRemainderOfOrder.Normalize()}, Free Margin: {freeMargin.Normalize()}");
94  }
95 
96  /// <summary>
97  /// Returns a string message saying the given target order margin is less than the given minimum value
98  /// </summary>
99  [MethodImpl(MethodImplOptions.AggressiveInlining)]
100  public static string TargetOrderMarginNotAboveMinimum(decimal absDifferenceOfMargin, decimal minimumValue)
101  {
102  return Invariant($"The target order margin {absDifferenceOfMargin} is less than the minimum {minimumValue}.");
103  }
104 
105  /// <summary>
106  /// Returns a string message warning the user that the Portfolio rebalance result ignored as it resulted in
107  /// a single share trade recommendation which can generate high fees.
108  /// </summary>
109  [MethodImpl(MethodImplOptions.AggressiveInlining)]
110  public static string TargetOrderMarginNotAboveMinimum()
111  {
112  return "Warning: Portfolio rebalance result ignored as it resulted in a single share trade recommendation which can generate high fees." +
113  " To disable minimum order size checks please set Settings.MinimumOrderMarginPortfolioPercentage = 0.";
114  }
115 
116  /// <summary>
117  /// Returns a string message saying that the order quantity is less that the lot size of the given security
118  /// and that it has been rounded to zero
119  /// </summary>
120  [MethodImpl(MethodImplOptions.AggressiveInlining)]
121  public static string OrderQuantityLessThanLotSize(Securities.Security security, decimal targetOrderMargin)
122  {
123  return Invariant($@"The order quantity is less than the lot size of {
124  security.SymbolProperties.LotSize} and has been rounded to zero. Target order margin {targetOrderMargin}. ");
125  }
126 
127  /// <summary>
128  /// Returns a string message saying GetMaximumOrderQuantityForTargetBuyingPower failed to converge on the target margin.
129  /// It also contains useful information to reproduce the issue
130  /// </summary>
131  [MethodImpl(MethodImplOptions.AggressiveInlining)]
133  decimal signedTargetFinalMarginValue, decimal orderFees)
134  {
135  return Invariant($@"GetMaximumOrderQuantityForTargetBuyingPower failed to converge on the target margin: {
136  signedTargetFinalMarginValue}; the following information can be used to reproduce the issue. Total Portfolio Cash: {
137  parameters.Portfolio.Cash}; Security : {parameters.Security.Symbol.ID}; Price : {parameters.Security.Close}; Leverage: {
138  parameters.Security.Leverage}; Order Fee: {orderFees}; Lot Size: {
139  parameters.Security.SymbolProperties.LotSize}; Current Holdings: {parameters.Security.Holdings.Quantity} @ {
140  parameters.Security.Holdings.AveragePrice}; Target Percentage: %{parameters.TargetBuyingPower * 100};");
141  }
142 
143  /// <summary>
144  /// Returns a string message containing basic information related with the underlying security such as the price,
145  /// the holdings and the average price of them
146  /// </summary>
147  [MethodImpl(MethodImplOptions.AggressiveInlining)]
148  public static string FailedToConvergeOnTheTargetMarginUnderlyingSecurityInfo(Securities.Security underlying)
149  {
150  return Invariant($@"Underlying Security: {underlying.Symbol.ID}; Underlying Price: {
151  underlying.Close}; Underlying Holdings: {underlying.Holdings.Quantity} @ {underlying.Holdings.AveragePrice};");
152  }
153 
154  /// <summary>
155  /// Returns a string message saying the margin is being adjusted in the wrong direction. It also provides useful information to
156  /// reproduce the issue
157  /// </summary>
158  [MethodImpl(MethodImplOptions.AggressiveInlining)]
159  public static string MarginBeingAdjustedInTheWrongDirection(decimal targetMargin, decimal marginForOneUnit, Securities.Security security)
160  {
161  return Invariant(
162  $@"Margin is being adjusted in the wrong direction. Reproduce this issue with the following variables, Target Margin: {
163  targetMargin}; MarginForOneUnit: {marginForOneUnit}; Security Holdings: {security.Holdings.Quantity} @ {
164  security.Holdings.AveragePrice}; LotSize: {security.SymbolProperties.LotSize}; Price: {security.Close}; Leverage: {
165  security.Leverage}");
166  }
167 
168  /// <summary>
169  /// Returns a string message containing basic information related with the underlying security such as the price,
170  /// the holdings and the average price of them
171  /// </summary>
172  [MethodImpl(MethodImplOptions.AggressiveInlining)]
173  public static string MarginBeingAdjustedInTheWrongDirectionUnderlyingSecurityInfo(Securities.Security underlying)
174  {
175  return Invariant($@"Underlying Security: {underlying.Symbol.ID}; Underlying Price: {
176  underlying.Close}; Underlying Holdings: {underlying.Holdings.Quantity} @ {underlying.Holdings.AveragePrice};");
177  }
178  }
179 
180  /// <summary>
181  /// Provides user-facing messages for the <see cref="Securities.Positions.PositionGroupBuyingPowerModel"/> class and its consumers or related classes
182  /// </summary>
183  public static class PositionGroupBuyingPowerModel
184  {
185  /// <summary>
186  /// String message saying: No buying power used, delta cannot be applied
187  /// </summary>
188  public static string DeltaCannotBeApplied = "No buying power used, delta cannot be applied";
189 
190  /// <summary>
191  /// Returns a string message saying the zero initial margin requirement was computed
192  /// for the given position group
193  /// </summary>
194  [MethodImpl(MethodImplOptions.AggressiveInlining)]
195  public static string ComputedZeroInitialMargin(IPositionGroup positionGroup)
196  {
197  return Invariant($"Computed zero initial margin requirement for {positionGroup.GetUserFriendlyName()}.");
198  }
199 
200  /// <summary>
201  /// Returns a string message saying the position group order quantity has been rounded to zero
202  /// </summary>
203  [MethodImpl(MethodImplOptions.AggressiveInlining)]
204  public static string PositionGroupQuantityRoundedToZero(decimal targetOrderMargin)
205  {
206  return Invariant($"The position group order quantity has been rounded to zero. Target order margin {targetOrderMargin}.");
207  }
208 
209  /// <summary>
210  /// Returns a string message saying the process to converge on the given target margin failed
211  /// </summary>
212  [MethodImpl(MethodImplOptions.AggressiveInlining)]
213  public static string FailedToConvergeOnTargetMargin(decimal targetMargin, decimal positionGroupQuantity, decimal orderFees,
215  {
216  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};");
217  }
218  }
219 
220  /// <summary>
221  /// Provides user-facing messages for the <see cref="Securities.Cash"/> class and its consumers or related classes
222  /// </summary>
223  public static class Cash
224  {
225  /// <summary>
226  /// String message saying: Cash symbols cannot be null or empty
227  /// </summary>
228  public static string NullOrEmptyCashSymbol = "Cash symbols cannot be null or empty.";
229 
230  /// <summary>
231  /// Returns a string message saying no tradeable pair was found for the given currency symbol. It also mentions
232  /// that the given account currency will be set to zero
233  /// </summary>
234  [MethodImpl(MethodImplOptions.AggressiveInlining)]
235  public static string NoTradablePairFoundForCurrencyConversion(string cashCurrencySymbol, string accountCurrency,
236  IEnumerable<KeyValuePair<SecurityType, string>> marketMap)
237  {
238  return Invariant($@"No tradeable pair was found for currency {cashCurrencySymbol}, conversion rate to account currency ({
239  accountCurrency}) will be set to zero. Markets: [{string.Join(",", marketMap.Select(x => $"{x.Key}:{x.Value}"))}]");
240  }
241 
242  /// <summary>
243  /// Returns a string message saying the security symbol is being added for cash currency feed (this comes from the
244  /// given cash currency symbol)
245  /// </summary>
246  [MethodImpl(MethodImplOptions.AggressiveInlining)]
247  public static string AddingSecuritySymbolForCashCurrencyFeed(QuantConnect.Symbol symbol, string cashCurrencySymbol)
248  {
249  return Invariant($"Adding {symbol.Value} {symbol.ID.Market} for cash {cashCurrencySymbol} currency feed");
250  }
251 
252  /// <summary>
253  /// Parses the given Cash object into a string containing basic information about it
254  /// </summary>
255  [MethodImpl(MethodImplOptions.AggressiveInlining)]
256  public static string ToString(Securities.Cash cash, string accountCurrency)
257  {
258  // round the conversion rate for output
259  var rate = cash.ConversionRate;
260  rate = rate < 1000 ? rate.RoundToSignificantDigits(5) : Math.Round(rate, 2);
261  return Invariant($@"{cash.Symbol}: {cash.CurrencySymbol}{cash.Amount,15:0.00} @ {rate,10:0.00####} = {
262  QuantConnect.Currencies.GetCurrencySymbol(accountCurrency)}{Math.Round(cash.ValueInAccountCurrency, 2)}");
263  }
264  }
265 
266  /// <summary>
267  /// Provides user-facing messages for the <see cref="Securities.CashBook"/> class and its consumers or related classes
268  /// </summary>
269  public static class CashBook
270  {
271  /// <summary>
272  /// String message saying: Unexpected request for NullCurrency Cash instance
273  /// </summary>
274  public static string UnexpectedRequestForNullCurrency = "Unexpected request for NullCurrency Cash instance";
275 
276  /// <summary>
277  /// Returns a string message saying the conversion rate for the given currency is not available
278  /// </summary>
279  [MethodImpl(MethodImplOptions.AggressiveInlining)]
280  public static string ConversionRateNotFound(string currency)
281  {
282  return Invariant($"The conversion rate for {currency} is not available.");
283  }
284 
285  /// <summary>
286  /// Parses the given CashBook into a string mesage with basic information about it
287  /// </summary>
288  [MethodImpl(MethodImplOptions.AggressiveInlining)]
289  public static string ToString(Securities.CashBook cashBook)
290  {
291  var sb = new StringBuilder();
292  sb.AppendLine(Invariant($"Symbol {"Quantity",13} {"Conversion",10} = Value in {cashBook.AccountCurrency}"));
293  foreach (var value in cashBook.Values)
294  {
295  sb.AppendLine(value.ToString(cashBook.AccountCurrency));
296  }
297  sb.AppendLine("-------------------------------------------------");
298  sb.AppendLine(Invariant($@"CashBook Total Value: {
299  QuantConnect.Currencies.GetCurrencySymbol(cashBook.AccountCurrency)}{
300  Math.Round(cashBook.TotalValueInAccountCurrency, 2).ToStringInvariant()}"));
301 
302  return sb.ToString();
303  }
304 
305  /// <summary>
306  /// Returns a string message saying the given cash symbol was not found
307  /// </summary>
308  [MethodImpl(MethodImplOptions.AggressiveInlining)]
309  public static string CashSymbolNotFound(string symbol)
310  {
311  return $"This cash symbol ({symbol}) was not found in your cash book.";
312  }
313 
314  /// <summary>
315  /// Returns a string message saying it was impossible to remove the cash book record
316  /// for the given symbol
317  /// </summary>
318  [MethodImpl(MethodImplOptions.AggressiveInlining)]
319  public static string FailedToRemoveRecord(string symbol)
320  {
321  return $"Failed to remove the cash book record for symbol {symbol}";
322  }
323  }
324 
325  /// <summary>
326  /// Provides user-facing messages for the <see cref="Securities.CashBuyingPowerModel"/> class and its consumers or related classes
327  /// </summary>
328  public static class CashBuyingPowerModel
329  {
330  /// <summary>
331  /// String message saying: CashBuyingPowerModel does not allow setting leverage. Cash accounts have no leverage
332  /// </summary>
333  public static string UnsupportedLeverage = "CashBuyingPowerModel does not allow setting leverage. Cash accounts have no leverage.";
334 
335  /// <summary>
336  /// String message saying: The CashBuyingPowerModel does not require GetMaximumOrderQuantityForDeltaBuyingPower
337  /// </summary>
339  $@"The {nameof(CashBuyingPowerModel)} does not require '{
340  nameof(Securities.CashBuyingPowerModel.GetMaximumOrderQuantityForDeltaBuyingPower)}'.";
341 
342  /// <summary>
343  /// String message saying: The cash model does not allow shorting
344  /// </summary>
345  public static string ShortingNotSupported = "The cash model does not allow shorting.";
346 
347  /// <summary>
348  /// String message saying: The security type must be Crypto or Forex
349  /// </summary>
350  public static string InvalidSecurity = $"The security type must be {nameof(SecurityType.Crypto)}or {nameof(SecurityType.Forex)}.";
351 
352  /// <summary>
353  /// Returns a string message saying: The security is not supported by this cash model. It also mentioned that
354  /// currently just crypt and forex securities are supported
355  /// </summary>
356  [MethodImpl(MethodImplOptions.AggressiveInlining)]
357  public static string UnsupportedSecurity(Securities.Security security)
358  {
359  return $@"The '{security.Symbol.Value}' security is not supported by this cash model. Currently only {
360  nameof(SecurityType.Crypto)} and {nameof(SecurityType.Forex)} are supported.";
361  }
362 
363  /// <summary>
364  /// Returns a string message saying Cash Modeling trading does not permit short holdings as well as portfolio
365  /// holdings and an advise to ensure the user is selling only what it has
366  /// </summary>
367  [MethodImpl(MethodImplOptions.AggressiveInlining)]
368  public static string SellOrderShortHoldingsNotSupported(decimal totalQuantity, decimal openOrdersReservedQuantity, decimal orderQuantity,
369  IBaseCurrencySymbol baseCurrency)
370  {
371  return Invariant($@"Your portfolio holds {totalQuantity.Normalize()} {
372  baseCurrency.BaseCurrency.Symbol}, {openOrdersReservedQuantity.Normalize()} {
373  baseCurrency.BaseCurrency.Symbol} of which are reserved for open orders, but your Sell order is for {
374  orderQuantity.Normalize()} {baseCurrency.BaseCurrency.Symbol
375  }. Cash Modeling trading does not permit short holdings so ensure you only sell what you have, including any additional open orders.");
376  }
377 
378  /// <summary>
379  /// Returns a string message containing the portfolio holdings, the buy order and the maximum buying power
380  /// </summary>
381  [MethodImpl(MethodImplOptions.AggressiveInlining)]
382  public static string BuyOrderQuantityGreaterThanMaxForBuyingPower(decimal totalQuantity, decimal maximumQuantity,
383  decimal openOrdersReservedQuantity, decimal orderQuantity, IBaseCurrencySymbol baseCurrency, Securities.Security security,
384  Orders.Order order)
385  {
386  return Invariant($@"Your portfolio holds {totalQuantity.Normalize()} {
387  security.QuoteCurrency.Symbol}, {openOrdersReservedQuantity.Normalize()} {
388  security.QuoteCurrency.Symbol} of which are reserved for open orders, but your Buy order is for {
389  order.AbsoluteQuantity.Normalize()} {baseCurrency.BaseCurrency.Symbol}. Your order requires a total value of {
390  orderQuantity.Normalize()} {security.QuoteCurrency.Symbol}, but only a total value of {
391  Math.Abs(maximumQuantity).Normalize()} {security.QuoteCurrency.Symbol} is available.");
392  }
393 
394  /// <summary>
395  /// Returns a string message saying the internal cash feed required for converting the quote currency, from the given security,
396  /// to the target account currency, from the given portfolio, does not have any data
397  /// </summary>
398  [MethodImpl(MethodImplOptions.AggressiveInlining)]
399  public static string NoDataInInternalCashFeedYet(Securities.Security security, Securities.SecurityPortfolioManager portfolio)
400  {
401  return Invariant($@"The internal cash feed required for converting {security.QuoteCurrency.Symbol} to {
402  portfolio.CashBook.AccountCurrency} does not have any data yet (or market may be closed).");
403  }
404 
405  /// <summary>
406  /// Returns a string mesasge saying the contract multiplier for the given security is zero
407  /// </summary>
408  [MethodImpl(MethodImplOptions.AggressiveInlining)]
409  public static string ZeroContractMultiplier(Securities.Security security)
410  {
411  return $@"The contract multiplier for the {
412  security.Symbol.Value} security is zero. The symbol properties database may be out of date.";
413  }
414 
415  /// <summary>
416  /// Returns a string message saying the order quantity is less than the lot size for the given security
417  /// </summary>
418  [MethodImpl(MethodImplOptions.AggressiveInlining)]
419  public static string OrderQuantityLessThanLotSize(Securities.Security security)
420  {
421  return Invariant($@"The order quantity is less than the lot size of {
422  security.SymbolProperties.LotSize} and has been rounded to zero.");
423  }
424 
425  /// <summary>
426  /// Returns a string message containing information about the target order value, the order fees and
427  /// the order quantity
428  /// </summary>
429  [MethodImpl(MethodImplOptions.AggressiveInlining)]
430  public static string OrderQuantityLessThanLotSizeOrderDetails(decimal targetOrderValue, decimal orderQuantity, decimal orderFees)
431  {
432  return Invariant($"Target order value {targetOrderValue}. Order fees {orderFees}. Order quantity {orderQuantity}.");
433  }
434 
435  /// <summary>
436  /// Returns a string message saying GetMaximumOrderQuantityForTargetBuyingPower failed to converge to
437  /// the given target order value
438  /// </summary>
439  [MethodImpl(MethodImplOptions.AggressiveInlining)]
440  public static string FailedToConvergeOnTargetOrderValue(decimal targetOrderValue, decimal currentOrderValue, decimal orderQuantity,
441  decimal orderFees, Securities.Security security)
442  {
443  return Invariant($@"GetMaximumOrderQuantityForTargetBuyingPower failed to converge to target order value {
444  targetOrderValue}. Current order value is {currentOrderValue}. Order quantity {orderQuantity}. Lot size is {
445  security.SymbolProperties.LotSize}. Order fees {orderFees}. Security symbol {security.Symbol}");
446  }
447  }
448 
449  /// <summary>
450  /// Provides user-facing messages for the <see cref="Securities.DefaultMarginCallModel"/> class and its consumers or related classes
451  /// </summary>
452  public static class DefaultMarginCallModel
453  {
454  /// <summary>
455  /// String message saying: Margin Call
456  /// </summary>
457  public static string MarginCallOrderTag = "Margin Call";
458  }
459 
460  /// <summary>
461  /// Provides user-facing messages for the <see cref="Securities.DynamicSecurityData"/> class and its consumers or related classes
462  /// </summary>
463  public static class DynamicSecurityData
464  {
465  /// <summary>
466  /// String message saying: DynamicSecurityData is a view of the SecurityCache. It is readonly, properties can not bet set
467  /// </summary>
468  public static string PropertiesCannotBeSet =
469  "DynamicSecurityData is a view of the SecurityCache. It is readonly, properties can not be set";
470 
471  /// <summary>
472  /// Returns a string message saying no property exists with the given name
473  /// </summary>
474  [MethodImpl(MethodImplOptions.AggressiveInlining)]
475  public static string PropertyNotFound(string name)
476  {
477  return $"Property with name '{name}' does not exist.";
478  }
479 
480  /// <summary>
481  /// Returns a string message saying a list of the given type was expected but the one found was of the given data type
482  /// </summary>
483  [MethodImpl(MethodImplOptions.AggressiveInlining)]
484  public static string UnexpectedTypesForGetAll(Type type, object data)
485  {
486  return $"Expected a list with type '{type.GetBetterTypeName()}' but found type '{data.GetType().GetBetterTypeName()}";
487  }
488  }
489 
490  /// <summary>
491  /// Provides user-facing messages for the <see cref="Securities.EquityPriceVariationModel"/> class and its consumers or related classes
492  /// </summary>
493  public static class EquityPriceVariationModel
494  {
495  /// <summary>
496  /// Returns a string message saying the type of the given security was invalid
497  /// </summary>
498  [MethodImpl(MethodImplOptions.AggressiveInlining)]
499  public static string InvalidSecurityType(Securities.Security security)
500  {
501  return Invariant($"Invalid SecurityType: {security.Type}");
502  }
503  }
504 
505  /// <summary>
506  /// Provides user-facing messages for the <see cref="Securities.ErrorCurrencyConverter"/> class and its consumers or related classes
507  /// </summary>
508  public static class ErrorCurrencyConverter
509  {
510  /// <summary>
511  /// String message saying: Unexpected usage of ErrorCurrencyConverter.AccountCurrency
512  /// </summary>
513  public static string AccountCurrencyUnexpectedUsage = "Unexpected usage of ErrorCurrencyConverter.AccountCurrency";
514 
515  /// <summary>
516  /// String message saying: This method purposefully throws as a proof that a test does not depend on a currency converter
517  /// </summary>
519  $@"This method purposefully throws as a proof that a test does not depend on {
520  nameof(ICurrencyConverter)}. If this exception is encountered, it means the test DOES depend on {
521  nameof(ICurrencyConverter)} and should be properly updated to use a real implementation of {nameof(ICurrencyConverter)}.";
522  }
523 
524  /// <summary>
525  /// Provides user-facing messages for the <see cref="Securities.FuncSecuritySeeder"/> class and its consumers or related classes
526  /// </summary>
527  public static class FuncSecuritySeeder
528  {
529  /// <summary>
530  /// Returns a string message with basic information about the given BaseData object
531  /// </summary>
532  [MethodImpl(MethodImplOptions.AggressiveInlining)]
533  public static string SeededSecurityInfo(BaseData seedData)
534  {
535  return $"Seeded security: {seedData.Symbol.Value}: {seedData.GetType()} {seedData.Value}";
536  }
537 
538  /// <summary>
539  /// Returns a string message saying it was impossible to seed the given security
540  /// </summary>
541  [MethodImpl(MethodImplOptions.AggressiveInlining)]
542  public static string UnableToSeedSecurity(Securities.Security security)
543  {
544  return $"Unable to seed security: {security.Symbol.Value}";
545  }
546 
547  /// <summary>
548  /// Returns a string message saying it was impossible to seed price for the given security
549  /// </summary>
550  [MethodImpl(MethodImplOptions.AggressiveInlining)]
551  public static string UnableToSecurityPrice(Securities.Security security)
552  {
553  return $"Could not seed price for security {security.Symbol}";
554  }
555  }
556 
557  /// <summary>
558  /// Provides user-facing messages for the <see cref="Securities.IdentityCurrencyConverter"/> class and its consumers or related classes
559  /// </summary>
560  public static class IdentityCurrencyConverter
561  {
562  /// <summary>
563  /// String message saying: The IdentityCurrencyConverter can only handle CashAmounts in units of the account currency
564  /// </summary>
566  $"The {nameof(Securities.IdentityCurrencyConverter)} can only handle CashAmounts in units of the account currency";
567  }
568 
569  /// <summary>
570  /// Provides user-facing messages for the <see cref="Securities.InitialMarginParameters"/> class and its consumers or related classes
571  /// </summary>
572  public static class InitialMarginParameters
573  {
574  /// <summary>
575  /// String message saying: ForUnderlying is only invokable for IDerivativeSecurity (Option|Future)
576  /// </summary>
578  "ForUnderlying is only invokable for IDerivativeSecurity (Option|Future)";
579  }
580 
581  /// <summary>
582  /// Provides user-facing messages for the <see cref="Securities.LocalMarketHours"/> class and its consumers or related classes
583  /// </summary>
584  public static class LocalMarketHours
585  {
586  /// <summary>
587  /// Parses the given LocalMarketHours object into a string message containing basic information about it
588  /// </summary>
589  [MethodImpl(MethodImplOptions.AggressiveInlining)]
590  public static string ToString(Securities.LocalMarketHours instance)
591  {
592  if (instance.IsClosedAllDay)
593  {
594  return "Closed All Day";
595  }
596 
597  if (instance.IsOpenAllDay)
598  {
599  return "Open All Day";
600  }
601 
602  return Invariant($"{instance.DayOfWeek}: {string.Join(" | ", instance.Segments)}");
603  }
604  }
605 
606  /// <summary>
607  /// Provides user-facing messages for the <see cref="Securities.MaintenanceMarginParameters"/> class and its consumers or related classes
608  /// </summary>
609  public static class MaintenanceMarginParameters
610  {
611  /// <summary>
612  /// String message saying: ForUnderlying is only invokable for IDerivativeSecurity
613  /// </summary>
615  "ForUnderlying is only invokable for IDerivativeSecurity (Option|Future)";
616  }
617 
618  /// <summary>
619  /// Provides user-facing messages for the <see cref="Securities.MarketHoursDatabase"/> class and its consumers or related classes
620  /// </summary>
621  public static class MarketHoursDatabase
622  {
623  /// <summary>
624  /// String message saying: Future.Usa market type is no longer supported as we mapped each ticker to its actual exchange
625  /// </summary>
627  "Future.Usa market type is no longer supported as we mapped each ticker to its actual exchange. " +
628  "Please find your specific market in the symbol-properties database.";
629 
630  /// <summary>
631  /// Returns a string message saying it was impossible to locate exchange hours for the given key. It also
632  /// mentiones the available keys
633  /// </summary>
634  [MethodImpl(MethodImplOptions.AggressiveInlining)]
635  public static string ExchangeHoursNotFound(Securities.SecurityDatabaseKey key,
636  IEnumerable<Securities.SecurityDatabaseKey> availableKeys = null)
637  {
638  var keys = "";
639  if (availableKeys != null)
640  {
641  keys = " Available keys: " + string.Join(", ", availableKeys);
642  }
643 
644  return $"Unable to locate exchange hours for {key}.{keys}";
645  }
646 
647  /// <summary>
648  /// Returns a string message that suggests the given market based on the provided ticker
649  /// </summary>
650  [MethodImpl(MethodImplOptions.AggressiveInlining)]
651  public static string SuggestedMarketBasedOnTicker(string market)
652  {
653  return $"Suggested market based on the provided ticker 'Market.{market.ToUpperInvariant()}'.";
654  }
655  }
656 
657  /// <summary>
658  /// Provides user-facing messages for the <see cref="Securities.MarketHoursSegment"/> class and its consumers or related classes
659  /// </summary>
660  public static class MarketHoursSegment
661  {
662  /// <summary>
663  /// String message saying: Extended market open time must be less than or equal to market open time
664  /// </summary>
665  public static string InvalidExtendedMarketOpenTime = "Extended market open time must be less than or equal to market open time.";
666 
667  /// <summary>
668  /// String message saying: Market close time must be after market open time
669  /// </summary>
670  public static string InvalidMarketCloseTime = "Market close time must be after market open time.";
671 
672  /// <summary>
673  /// String message saying: Extended market close time must be greater than or equal to market close time
674  /// </summary>
675  public static string InvalidExtendedMarketCloseTime = "Extended market close time must be greater than or equal to market close time.";
676 
677  /// <summary>
678  /// Parses a MarketHourSegment object into a string message containing basic information about it
679  /// </summary>
680  [MethodImpl(MethodImplOptions.AggressiveInlining)]
681  public static string ToString(Securities.MarketHoursSegment instance)
682  {
683  return $"{instance.State}: {instance.Start.ToStringInvariant(null)}-{instance.End.ToStringInvariant(null)}";
684  }
685  }
686 
687  /// <summary>
688  /// Provides user-facing messages for the <see cref="Securities.RegisteredSecurityDataTypesProvider"/> class and its consumers or related classes
689  /// </summary>
691  {
692  /// <summary>
693  /// Returns a string message saying two different types were detected trying to register the same type name. It also
694  /// mentions the two different types
695  /// </summary>
696  [MethodImpl(MethodImplOptions.AggressiveInlining)]
697  public static string TwoDifferentTypesDetectedForTheSameTypeName(Type type, Type existingType)
698  {
699  return $"Two different types were detected trying to register the same type name: {existingType} - {type}";
700  }
701  }
702 
703  /// <summary>
704  /// Provides user-facing messages for the <see cref="Securities.Security"/> class and its consumers or related classes
705  /// </summary>
706  public static class Security
707  {
708  /// <summary>
709  /// String message saying: Security requires a valid SymbolProperties instance
710  /// </summary>
711  public static string ValidSymbolPropertiesInstanceRequired = "Security requires a valid SymbolProperties instance.";
712 
713  /// <summary>
714  /// String message saying: symbolProperties.QuoteCurrency must match the quoteCurrency.Symbol
715  /// </summary>
716  public static string UnmatchingQuoteCurrencies = "symbolProperties.QuoteCurrency must match the quoteCurrency.Symbol";
717 
718  /// <summary>
719  /// String message saying: Security.SetLocalTimeKeeper(LocalTimeKeeper) must be called in order to use the LocalTime property
720  /// </summary>
722  "Security.SetLocalTimeKeeper(LocalTimeKeeper) must be called in order to use the LocalTime property.";
723 
724  /// <summary>
725  /// String message saying: Symbols must match
726  /// </summary>
727  public static string UnmatchingSymbols = "Symbols must match.";
728 
729  /// <summary>
730  /// String message saying: ExchangeTimeZones must match
731  /// </summary>
732  public static string UnmatchingExchangeTimeZones = "ExchangeTimeZones must match.";
733  }
734 
735  /// <summary>
736  /// Provides user-facing messages for the <see cref="Securities.SecurityDatabaseKey"/> class and its consumers or related classes
737  /// </summary>
738  public static class SecurityDatabaseKey
739  {
740  /// <summary>
741  /// Returns a string message saying the specified and given key was not in the expected format
742  /// </summary>
743  [MethodImpl(MethodImplOptions.AggressiveInlining)]
744  public static string KeyNotInExpectedFormat(string key)
745  {
746  return $"The specified key was not in the expected format: {key}";
747  }
748 
749  /// <summary>
750  /// Parses a SecurityDatabaseKey into a string message with basic information about it
751  /// </summary>
752  [MethodImpl(MethodImplOptions.AggressiveInlining)]
753  public static string ToString(Securities.SecurityDatabaseKey instance)
754  {
755  return Invariant($"{instance.SecurityType}-{instance.Market}-{instance.Symbol}");
756  }
757  }
758 
759  /// <summary>
760  /// Provides user-facing messages for the <see cref="Securities.SecurityDefinitionSymbolResolver"/> class and its consumers or related classes
761  /// </summary>
763  {
764  /// <summary>
765  /// Returns a string message saying no security definitions data have been loaded from the given file
766  /// </summary>
767  [MethodImpl(MethodImplOptions.AggressiveInlining)]
768  public static string NoSecurityDefinitionsLoaded(string securitiesDefinitionKey)
769  {
770  return $"No security definitions data loaded from file: {securitiesDefinitionKey}";
771  }
772  }
773 
774  /// <summary>
775  /// Provides user-facing messages for the <see cref="Securities.SecurityExchangeHours"/> class and its consumers or related classes
776  /// </summary>
777  public static class SecurityExchangeHours
778  {
779  /// <summary>
780  /// String message saying: Unable to locate next market open within two weeks
781  /// </summary>
782  public static string UnableToLocateNextMarketOpenInTwoWeeks = "Unable to locate next market open within two weeks.";
783 
784  /// <summary>
785  /// String message saying: Unable to locate next market close within two weeks
786  /// </summary>
787  public static string UnableToLocateNextMarketCloseInTwoWeeks = "Unable to locate next market close within two weeks.";
788 
789  /// <summary>
790  /// Returns a string message saying it did not find last market open for the given local date time. It also mentions
791  /// if the market is always open or not
792  /// </summary>
793  [MethodImpl(MethodImplOptions.AggressiveInlining)]
794  public static string LastMarketOpenNotFound(DateTime localDateTime, bool isMarketAlwaysOpen)
795  {
796  return $"Did not find last market open for {localDateTime}. IsMarketAlwaysOpen: {isMarketAlwaysOpen}";
797  }
798  }
799 
800  /// <summary>
801  /// Provides user-facing messages for the <see cref="Securities.SecurityHolding"/> class and its consumers or related classes
802  /// </summary>
803  public static class SecurityHolding
804  {
805  /// <summary>
806  /// Parses the given SecurityHolding object into a string message containing basic information about it
807  /// </summary>
808  [MethodImpl(MethodImplOptions.AggressiveInlining)]
809  public static string ToString(Securities.SecurityHolding instance)
810  {
811  return Invariant($"{instance.Symbol.Value}: {instance.Quantity} @ {instance.AveragePrice}");
812  }
813  }
814 
815  /// <summary>
816  /// Provides user-facing messages for the <see cref="Securities.SecurityManager"/> class and its consumers or related classes
817  /// </summary>
818  public static class SecurityManager
819  {
820  /// <summary>
821  /// Returns a string message saying the given symbol was not found in the user security list
822  /// </summary>
823  [MethodImpl(MethodImplOptions.AggressiveInlining)]
824  public static string SymbolNotFoundInSecurities(QuantConnect.Symbol symbol)
825  {
826  return Invariant($@"This asset symbol ({
827  symbol}) was not found in your security list. Please add this security or check it exists before using it with 'Securities.ContainsKey(""{
828  QuantConnect.SymbolCache.GetTicker(symbol)}"")'");
829  }
830 
831  /// <summary>
832  /// Returns a string message saying the given symbol could not be overwritten
833  /// </summary>
834  [MethodImpl(MethodImplOptions.AggressiveInlining)]
835  public static string UnableToOverwriteSecurity(QuantConnect.Symbol symbol)
836  {
837  return Invariant($"Unable to overwrite existing Security: {symbol}");
838  }
839  }
840 
841  /// <summary>
842  /// Provides user-facing messages for the <see cref="Securities.SecurityPortfolioManager"/> class and its consumers or related classes
843  /// </summary>
844  public static class SecurityPortfolioManager
845  {
846  /// <summary>
847  /// Returns a string message saying Portfolio object is an adaptor for Security Manager and that to add a new asset
848  /// the required data should added during initialization
849  /// </summary>
850  public static string DictionaryAddNotImplemented =
851  "Portfolio object is an adaptor for Security Manager. To add a new asset add the required data during initialization.";
852 
853  /// <summary>
854  /// Returns a string message saying the Portfolio object object is an adaptor for Security Manager and cannot be cleared
855  /// </summary>
856  public static string DictionaryClearNotImplemented = "Portfolio object is an adaptor for Security Manager and cannot be cleared.";
857 
858  /// <summary>
859  /// Returns a string message saying the Portfolio object is an adaptor for Security Manager and objects cannot be removed
860  /// </summary>
861  public static string DictionaryRemoveNotImplemented = "Portfolio object is an adaptor for Security Manager and objects cannot be removed.";
862 
863  /// <summary>
864  /// Returns a string message saying the AccountCurrency cannot be changed after adding a Security and that the method
865  /// SetAccountCurrency() should be moved before AddSecurity()
866  /// </summary>
868  "Cannot change AccountCurrency after adding a Security. Please move SetAccountCurrency() before AddSecurity().";
869 
870  /// <summary>
871  /// Returns a string message saying the AccountCurrency cannot be changed after setting cash and that the method
872  /// SetAccountCurrency() should be moved before SetCash()
873  /// </summary>
875  "Cannot change AccountCurrency after setting cash. Please move SetAccountCurrency() before SetCash().";
876 
877  /// <summary>
878  /// Returns a string message saying the AccountCurrency has already been set and that the new value for this property
879  /// will be ignored
880  /// </summary>
881  [MethodImpl(MethodImplOptions.AggressiveInlining)]
882  public static string AccountCurrencyAlreadySet(Securities.CashBook cashBook, string newAccountCurrency)
883  {
884  return $"account currency has already been set to {cashBook.AccountCurrency}. Will ignore new value {newAccountCurrency}";
885  }
886 
887  /// <summary>
888  /// Returns a string message saying the AccountCurrency is being set to the given account currency
889  /// </summary>
890  [MethodImpl(MethodImplOptions.AggressiveInlining)]
891  public static string SettingAccountCurrency(string accountCurrency)
892  {
893  return $"setting account currency to {accountCurrency}";
894  }
895 
896  /// <summary>
897  /// Returns a string message saying the total margin information, this is, the total margin used as well as the
898  /// margin remaining
899  /// </summary>
900  [MethodImpl(MethodImplOptions.AggressiveInlining)]
901  public static string TotalMarginInformation(decimal totalMarginUsed, decimal marginRemaining)
902  {
903  return Invariant($"Total margin information: TotalMarginUsed: {totalMarginUsed:F2}, MarginRemaining: {marginRemaining:F2}");
904  }
905 
906  /// <summary>
907  /// Returns a string message saying the order request margin information, this is, the margin used and the margin remaining
908  /// </summary>
909  [MethodImpl(MethodImplOptions.AggressiveInlining)]
910  public static string OrderRequestMarginInformation(decimal marginUsed, decimal marginRemaining)
911  {
912  return Invariant($"Order request margin information: MarginUsed: {marginUsed:F2}, MarginRemaining: {marginRemaining:F2}");
913  }
914  }
915 
916  /// <summary>
917  /// Provides user-facing messages for the <see cref="Securities.SecurityService"/> class and its consumers or related classes
918  /// </summary>
919  public static class SecurityService
920  {
921  /// <summary>
922  /// Returns a string message saying the given Symbol could not be found in the Symbol Properties Database
923  /// </summary>
924  [MethodImpl(MethodImplOptions.AggressiveInlining)]
926  {
927  return $"Symbol could not be found in the Symbol Properties Database: {symbol.Value}";
928  }
929  }
930 
931  /// <summary>
932  /// Provides user-facing messages for the <see cref="Securities.SecurityTransactionManager"/> class and its consumers or related classes
933  /// </summary>
934  public static class SecurityTransactionManager
935  {
936  /// <summary>
937  /// Returns a string message saying CancelOpenOrders operation is not allowed in Initialize or during warm up
938  /// </summary>
940  "This operation is not allowed in Initialize or during warm up: CancelOpenOrders. Please move this code to the OnWarmupFinished() method.";
941 
942  /// <summary>
943  /// Returns a string message saying the order was canceled by the CancelOpenOrders() at the given time
944  /// </summary>
945  [MethodImpl(MethodImplOptions.AggressiveInlining)]
946  public static string OrderCanceledByCancelOpenOrders(DateTime time)
947  {
948  return Invariant($"Canceled by CancelOpenOrders() at {time:o}");
949  }
950 
951  /// <summary>
952  /// Returns a string message saying the ticket for the given order ID could not be localized
953  /// </summary>
954  [MethodImpl(MethodImplOptions.AggressiveInlining)]
955  public static string UnableToLocateOrderTicket(int orderId)
956  {
957  return Invariant($"Unable to locate ticket for order: {orderId}");
958  }
959 
960  /// <summary>
961  /// Returns a string message saying the order did not fill within the given amount of seconds
962  /// </summary>
963  [MethodImpl(MethodImplOptions.AggressiveInlining)]
964  public static string OrderNotFilledWithinExpectedTime(TimeSpan fillTimeout)
965  {
966  return Invariant($"Order did not fill within {fillTimeout.TotalSeconds} seconds.");
967  }
968  }
969 
970  /// <summary>
971  /// Provides user-facing messages for the <see cref="Securities.SymbolProperties"/> class and its consumers or related classes
972  /// </summary>
973  public static class SymbolProperties
974  {
975  /// <summary>
976  /// String message saying the SymbolProperties LotSize can not be less than or equal to 0
977  /// </summary>
978  public static string InvalidLotSize = "SymbolProperties LotSize can not be less than or equal to 0";
979 
980  /// <summary>
981  /// String message saying the SymbolProperties PriceMagnifier can not be less than or equal to 0
982  /// </summary>
983  public static string InvalidPriceMagnifier = "SymbolProprties PriceMagnifier can not be less than or equal to 0";
984 
985  /// <summary>
986  /// String message saying the SymbolProperties StrikeMultiplier can not be less than or equal to 0
987  /// </summary>
988  public static string InvalidStrikeMultiplier = "SymbolProperties StrikeMultiplier can not be less than or equal to 0";
989 
990  /// <summary>
991  /// Parses a given SymbolProperties object into a string message
992  /// </summary>
993  [MethodImpl(MethodImplOptions.AggressiveInlining)]
994  public static string ToString(Securities.SymbolProperties instance)
995  {
996  var marketTicker = ",";
997  var minimumOrderSize = marketTicker;
998  var priceMagnifier = marketTicker;
999  if (!string.IsNullOrEmpty(instance.MarketTicker))
1000  {
1001  marketTicker = $",{instance.MarketTicker}";
1002  }
1003  if (instance.MinimumOrderSize != null)
1004  {
1005  minimumOrderSize = Invariant($",{instance.MinimumOrderSize}");
1006  }
1007  if (instance.PriceMagnifier != 1)
1008  {
1009  priceMagnifier = Invariant($",{instance.PriceMagnifier}");
1010  }
1011 
1012  return Invariant($@"{instance.Description},{instance.QuoteCurrency},{instance.ContractMultiplier},{
1013  instance.MinimumPriceVariation},{instance.LotSize}{marketTicker}{minimumOrderSize}{priceMagnifier}");
1014  }
1015  }
1016 
1017  /// <summary>
1018  /// Provides user-facing messages for the <see cref="Securities.SymbolPropertiesDatabase"/> class and its consumers or related classes
1019  /// </summary>
1020  public static class SymbolPropertiesDatabase
1021  {
1022  //public static string InvalidLotSize = "SymbolProperties LotSize can not be less than or equal to 0";
1023 
1024  /// <summary>
1025  /// Returns a string saying a duplicated key was found while processing the given file
1026  /// </summary>
1027  [MethodImpl(MethodImplOptions.AggressiveInlining)]
1028  public static string DuplicateKeyInFile(string file, Securities.SecurityDatabaseKey key)
1029  {
1030  return $"Encountered duplicate key while processing file: {file}. Key: {key}";
1031  }
1032 
1033  /// <summary>
1034  /// Returns a string saying the given symbol properties file could not be localized
1035  /// </summary>
1036  [MethodImpl(MethodImplOptions.AggressiveInlining)]
1037  public static string DatabaseFileNotFound(string file)
1038  {
1039  return $"Unable to locate symbol properties file: {file}";
1040  }
1041  }
1042  }
1043 }