/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using QuantConnect.Data; using QuantConnect.Securities; using QuantConnect.Securities.Positions; using static QuantConnect.StringExtensions; namespace QuantConnect { /// /// Provides user-facing message construction methods and static messages for the namespace /// public static partial class Messages { /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class AccountEvent { /// /// Returns a string message containing basic information about the given accountEvent /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToString(Securities.AccountEvent accountEvent) { return Invariant($"Account {accountEvent.CurrencySymbol} Balance: {accountEvent.CashBalance:0.00}"); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class BuyingPowerModel { /// /// String message saying: Initial margin requirement must be between 0 and 1 /// public static string InvalidInitialMarginRequirement = "Initial margin requirement must be between 0 and 1"; /// /// String messsage saying: Maintenance margin requirement must be between 0 and 1 /// public static string InvalidMaintenanceMarginRequirement = "Maintenance margin requirement must be between 0 and 1"; /// /// String message saying: Free Buying Power Percent requirement must be between 0 and 1 /// public static string InvalidFreeBuyingPowerPercentRequirement = "Free Buying Power Percent requirement must be between 0 and 1"; /// /// String message saying: Leverage must be greater than or equal to 1 /// public static string InvalidLeverage = "Leverage must be greater than or equal to 1."; /// /// Returns a string message saying the order associated with the id of the given order is null /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string InsufficientBuyingPowerDueToNullOrderTicket(Orders.Order order) { return Invariant($"Null order ticket for id: {order.Id}"); } /// /// Returns a string mesage containing information about the order ID, the initial margin and /// the free margin /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string InsufficientBuyingPowerDueToUnsufficientMargin(Orders.Order order, decimal initialMarginRequiredForRemainderOfOrder, decimal freeMargin) { return Invariant($@"Id: {order.Id}, Initial Margin: { initialMarginRequiredForRemainderOfOrder.Normalize()}, Free Margin: {freeMargin.Normalize()}"); } /// /// Returns a string message saying the given target order margin is less than the given minimum value /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string TargetOrderMarginNotAboveMinimum(decimal absDifferenceOfMargin, decimal minimumValue) { return Invariant($"The target order margin {absDifferenceOfMargin} is less than the minimum {minimumValue}."); } /// /// Returns a string message warning the user that the Portfolio rebalance result ignored as it resulted in /// a single share trade recommendation which can generate high fees. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string TargetOrderMarginNotAboveMinimum() { return "Warning: Portfolio rebalance result ignored as it resulted in a single share trade recommendation which can generate high fees." + " To disable minimum order size checks please set Settings.MinimumOrderMarginPortfolioPercentage = 0."; } /// /// Returns a string message saying that the order quantity is less that the lot size of the given security /// and that it has been rounded to zero /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string OrderQuantityLessThanLotSize(Securities.Security security, decimal targetOrderMargin) { return Invariant($@"The order quantity is less than the lot size of { security.SymbolProperties.LotSize} and has been rounded to zero. Target order margin {targetOrderMargin}. "); } /// /// Returns a string message saying GetMaximumOrderQuantityForTargetBuyingPower failed to converge on the target margin. /// It also contains useful information to reproduce the issue /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string FailedToConvergeOnTheTargetMargin(GetMaximumOrderQuantityForTargetBuyingPowerParameters parameters, decimal signedTargetFinalMarginValue, decimal orderFees) { return Invariant($@"GetMaximumOrderQuantityForTargetBuyingPower failed to converge on the target margin: { signedTargetFinalMarginValue}; the following information can be used to reproduce the issue. Total Portfolio Cash: { parameters.Portfolio.Cash}; Security : {parameters.Security.Symbol.ID}; Price : {parameters.Security.Close}; Leverage: { parameters.Security.Leverage}; Order Fee: {orderFees}; Lot Size: { parameters.Security.SymbolProperties.LotSize}; Current Holdings: {parameters.Security.Holdings.Quantity} @ { parameters.Security.Holdings.AveragePrice}; Target Percentage: %{parameters.TargetBuyingPower * 100};"); } /// /// Returns a string message containing basic information related with the underlying security such as the price, /// the holdings and the average price of them /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string FailedToConvergeOnTheTargetMarginUnderlyingSecurityInfo(Securities.Security underlying) { return Invariant($@"Underlying Security: {underlying.Symbol.ID}; Underlying Price: { underlying.Close}; Underlying Holdings: {underlying.Holdings.Quantity} @ {underlying.Holdings.AveragePrice};"); } /// /// Returns a string message saying the margin is being adjusted in the wrong direction. It also provides useful information to /// reproduce the issue /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string MarginBeingAdjustedInTheWrongDirection(decimal targetMargin, decimal marginForOneUnit, Securities.Security security) { return Invariant( $@"Margin is being adjusted in the wrong direction. Reproduce this issue with the following variables, Target Margin: { targetMargin}; MarginForOneUnit: {marginForOneUnit}; Security Holdings: {security.Holdings.Quantity} @ { security.Holdings.AveragePrice}; LotSize: {security.SymbolProperties.LotSize}; Price: {security.Close}; Leverage: { security.Leverage}"); } /// /// Returns a string message containing basic information related with the underlying security such as the price, /// the holdings and the average price of them /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string MarginBeingAdjustedInTheWrongDirectionUnderlyingSecurityInfo(Securities.Security underlying) { return Invariant($@"Underlying Security: {underlying.Symbol.ID}; Underlying Price: { underlying.Close}; Underlying Holdings: {underlying.Holdings.Quantity} @ {underlying.Holdings.AveragePrice};"); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class PositionGroupBuyingPowerModel { /// /// String message saying: No buying power used, delta cannot be applied /// public static string DeltaCannotBeApplied = "No buying power used, delta cannot be applied"; /// /// Returns a string message saying the zero initial margin requirement was computed /// for the given position group /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ComputedZeroInitialMargin(IPositionGroup positionGroup) { return Invariant($"Computed zero initial margin requirement for {positionGroup.GetUserFriendlyName()}."); } /// /// Returns a string message saying the position group order quantity has been rounded to zero /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string PositionGroupQuantityRoundedToZero(decimal targetOrderMargin) { return Invariant($"The position group order quantity has been rounded to zero. Target order margin {targetOrderMargin}."); } /// /// Returns a string message saying the process to converge on the given target margin failed /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string FailedToConvergeOnTargetMargin(decimal targetMargin, decimal positionGroupQuantity, decimal orderFees, GetMaximumLotsForTargetBuyingPowerParameters parameters) { 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};"); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class Cash { /// /// String message saying: Cash symbols cannot be null or empty /// public static string NullOrEmptyCashSymbol = "Cash symbols cannot be null or empty."; /// /// Returns a string message saying no tradeable pair was found for the given currency symbol. It also mentions /// that the given account currency will be set to zero /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string NoTradablePairFoundForCurrencyConversion(string cashCurrencySymbol, string accountCurrency, IEnumerable> marketMap) { return Invariant($@"No tradeable pair was found for currency {cashCurrencySymbol}, conversion rate to account currency ({ accountCurrency}) will be set to zero. Markets: [{string.Join(",", marketMap.Select(x => $"{x.Key}:{x.Value}"))}]"); } /// /// Returns a string message saying the security symbol is being added for cash currency feed (this comes from the /// given cash currency symbol) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string AddingSecuritySymbolForCashCurrencyFeed(QuantConnect.Symbol symbol, string cashCurrencySymbol) { return Invariant($"Adding {symbol.Value} {symbol.ID.Market} for cash {cashCurrencySymbol} currency feed"); } /// /// Parses the given Cash object into a string containing basic information about it /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToString(Securities.Cash cash, string accountCurrency) { // round the conversion rate for output var rate = cash.ConversionRate; rate = rate < 1000 ? rate.RoundToSignificantDigits(5) : Math.Round(rate, 2); return Invariant($@"{cash.Symbol}: {cash.CurrencySymbol}{cash.Amount,15:0.00} @ {rate,10:0.00####} = { QuantConnect.Currencies.GetCurrencySymbol(accountCurrency)}{Math.Round(cash.ValueInAccountCurrency, 2)}"); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class CashBook { /// /// String message saying: Unexpected request for NullCurrency Cash instance /// public static string UnexpectedRequestForNullCurrency = "Unexpected request for NullCurrency Cash instance"; /// /// Returns a string message saying the conversion rate for the given currency is not available /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ConversionRateNotFound(string currency) { return Invariant($"The conversion rate for {currency} is not available."); } /// /// Parses the given CashBook into a string mesage with basic information about it /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToString(Securities.CashBook cashBook) { var sb = new StringBuilder(); sb.AppendLine(Invariant($"Symbol {"Quantity",13} {"Conversion",10} = Value in {cashBook.AccountCurrency}")); foreach (var value in cashBook.Values) { sb.AppendLine(value.ToString(cashBook.AccountCurrency)); } sb.AppendLine("-------------------------------------------------"); sb.AppendLine(Invariant($@"CashBook Total Value: { QuantConnect.Currencies.GetCurrencySymbol(cashBook.AccountCurrency)}{ Math.Round(cashBook.TotalValueInAccountCurrency, 2).ToStringInvariant()}")); return sb.ToString(); } /// /// Returns a string message saying the given cash symbol was not found /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string CashSymbolNotFound(string symbol) { return $"This cash symbol ({symbol}) was not found in your cash book."; } /// /// Returns a string message saying it was impossible to remove the cash book record /// for the given symbol /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string FailedToRemoveRecord(string symbol) { return $"Failed to remove the cash book record for symbol {symbol}"; } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class CashBuyingPowerModel { /// /// String message saying: CashBuyingPowerModel does not allow setting leverage. Cash accounts have no leverage /// public static string UnsupportedLeverage = "CashBuyingPowerModel does not allow setting leverage. Cash accounts have no leverage."; /// /// String message saying: The CashBuyingPowerModel does not require GetMaximumOrderQuantityForDeltaBuyingPower /// public static string GetMaximumOrderQuantityForDeltaBuyingPowerNotImplemented = $@"The {nameof(CashBuyingPowerModel)} does not require '{ nameof(Securities.CashBuyingPowerModel.GetMaximumOrderQuantityForDeltaBuyingPower)}'."; /// /// String message saying: The cash model does not allow shorting /// public static string ShortingNotSupported = "The cash model does not allow shorting."; /// /// String message saying: The security type must be Crypto or Forex /// public static string InvalidSecurity = $"The security type must be {nameof(SecurityType.Crypto)}or {nameof(SecurityType.Forex)}."; /// /// Returns a string message saying: The security is not supported by this cash model. It also mentioned that /// currently just crypt and forex securities are supported /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string UnsupportedSecurity(Securities.Security security) { return $@"The '{security.Symbol.Value}' security is not supported by this cash model. Currently only { nameof(SecurityType.Crypto)} and {nameof(SecurityType.Forex)} are supported."; } /// /// Returns a string message saying Cash Modeling trading does not permit short holdings as well as portfolio /// holdings and an advise to ensure the user is selling only what it has /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string SellOrderShortHoldingsNotSupported(decimal totalQuantity, decimal openOrdersReservedQuantity, decimal orderQuantity, IBaseCurrencySymbol baseCurrency) { return Invariant($@"Your portfolio holds {totalQuantity.Normalize()} { baseCurrency.BaseCurrency.Symbol}, {openOrdersReservedQuantity.Normalize()} { baseCurrency.BaseCurrency.Symbol} of which are reserved for open orders, but your Sell order is for { orderQuantity.Normalize()} {baseCurrency.BaseCurrency.Symbol }. Cash Modeling trading does not permit short holdings so ensure you only sell what you have, including any additional open orders."); } /// /// Returns a string message containing the portfolio holdings, the buy order and the maximum buying power /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string BuyOrderQuantityGreaterThanMaxForBuyingPower(decimal totalQuantity, decimal maximumQuantity, decimal openOrdersReservedQuantity, decimal orderQuantity, IBaseCurrencySymbol baseCurrency, Securities.Security security, Orders.Order order) { return Invariant($@"Your portfolio holds {totalQuantity.Normalize()} { security.QuoteCurrency.Symbol}, {openOrdersReservedQuantity.Normalize()} { security.QuoteCurrency.Symbol} of which are reserved for open orders, but your Buy order is for { order.AbsoluteQuantity.Normalize()} {baseCurrency.BaseCurrency.Symbol}. Your order requires a total value of { orderQuantity.Normalize()} {security.QuoteCurrency.Symbol}, but only a total value of { Math.Abs(maximumQuantity).Normalize()} {security.QuoteCurrency.Symbol} is available."); } /// /// Returns a string message saying the internal cash feed required for converting the quote currency, from the given security, /// to the target account currency, from the given portfolio, does not have any data /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string NoDataInInternalCashFeedYet(Securities.Security security, Securities.SecurityPortfolioManager portfolio) { return Invariant($@"The internal cash feed required for converting {security.QuoteCurrency.Symbol} to { portfolio.CashBook.AccountCurrency} does not have any data yet (or market may be closed)."); } /// /// Returns a string mesasge saying the contract multiplier for the given security is zero /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ZeroContractMultiplier(Securities.Security security) { return $@"The contract multiplier for the { security.Symbol.Value} security is zero. The symbol properties database may be out of date."; } /// /// Returns a string message saying the order quantity is less than the lot size for the given security /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string OrderQuantityLessThanLotSize(Securities.Security security) { return Invariant($@"The order quantity is less than the lot size of { security.SymbolProperties.LotSize} and has been rounded to zero."); } /// /// Returns a string message containing information about the target order value, the order fees and /// the order quantity /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string OrderQuantityLessThanLotSizeOrderDetails(decimal targetOrderValue, decimal orderQuantity, decimal orderFees) { return Invariant($"Target order value {targetOrderValue}. Order fees {orderFees}. Order quantity {orderQuantity}."); } /// /// Returns a string message saying GetMaximumOrderQuantityForTargetBuyingPower failed to converge to /// the given target order value /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string FailedToConvergeOnTargetOrderValue(decimal targetOrderValue, decimal currentOrderValue, decimal orderQuantity, decimal orderFees, Securities.Security security) { return Invariant($@"GetMaximumOrderQuantityForTargetBuyingPower failed to converge to target order value { targetOrderValue}. Current order value is {currentOrderValue}. Order quantity {orderQuantity}. Lot size is { security.SymbolProperties.LotSize}. Order fees {orderFees}. Security symbol {security.Symbol}"); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class DefaultMarginCallModel { /// /// String message saying: Margin Call /// public static string MarginCallOrderTag = "Margin Call"; } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class DynamicSecurityData { /// /// String message saying: DynamicSecurityData is a view of the SecurityCache. It is readonly, properties can not bet set /// public static string PropertiesCannotBeSet = "DynamicSecurityData is a view of the SecurityCache. It is readonly, properties can not be set"; /// /// Returns a string message saying no property exists with the given name /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string PropertyNotFound(string name) { return $"Property with name '{name}' does not exist."; } /// /// Returns a string message saying a list of the given type was expected but the one found was of the given data type /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string UnexpectedTypesForGetAll(Type type, object data) { return $"Expected a list with type '{type.GetBetterTypeName()}' but found type '{data.GetType().GetBetterTypeName()}"; } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class EquityPriceVariationModel { /// /// Returns a string message saying the type of the given security was invalid /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string InvalidSecurityType(Securities.Security security) { return Invariant($"Invalid SecurityType: {security.Type}"); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class ErrorCurrencyConverter { /// /// String message saying: Unexpected usage of ErrorCurrencyConverter.AccountCurrency /// public static string AccountCurrencyUnexpectedUsage = "Unexpected usage of ErrorCurrencyConverter.AccountCurrency"; /// /// String message saying: This method purposefully throws as a proof that a test does not depend on a currency converter /// public static string ConvertToAccountCurrencyPurposefullyThrow = $@"This method purposefully throws as a proof that a test does not depend on { nameof(ICurrencyConverter)}. If this exception is encountered, it means the test DOES depend on { nameof(ICurrencyConverter)} and should be properly updated to use a real implementation of {nameof(ICurrencyConverter)}."; } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class FuncSecuritySeeder { /// /// Returns a string message with basic information about the given BaseData object /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string SeededSecurityInfo(BaseData seedData) { return $"Seeded security: {seedData.Symbol.Value}: {seedData.GetType()} {seedData.Value}"; } /// /// Returns a string message saying it was impossible to seed the given security /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string UnableToSeedSecurity(Securities.Security security) { return $"Unable to seed security: {security.Symbol.Value}"; } /// /// Returns a string message saying it was impossible to seed price for the given security /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string UnableToSecurityPrice(Securities.Security security) { return $"Could not seed price for security {security.Symbol}"; } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class IdentityCurrencyConverter { /// /// String message saying: The IdentityCurrencyConverter can only handle CashAmounts in units of the account currency /// public static string UnableToHandleCashInNonAccountCurrency = $"The {nameof(Securities.IdentityCurrencyConverter)} can only handle CashAmounts in units of the account currency"; } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class InitialMarginParameters { /// /// String message saying: ForUnderlying is only invokable for IDerivativeSecurity (Option|Future) /// public static string ForUnderlyingOnlyInvokableForIDerivativeSecurity = "ForUnderlying is only invokable for IDerivativeSecurity (Option|Future)"; } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class LocalMarketHours { /// /// Parses the given LocalMarketHours object into a string message containing basic information about it /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToString(Securities.LocalMarketHours instance) { if (instance.IsClosedAllDay) { return "Closed All Day"; } if (instance.IsOpenAllDay) { return "Open All Day"; } return Invariant($"{instance.DayOfWeek}: {string.Join(" | ", instance.Segments)}"); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class MaintenanceMarginParameters { /// /// String message saying: ForUnderlying is only invokable for IDerivativeSecurity /// public static string ForUnderlyingOnlyInvokableForIDerivativeSecurity = "ForUnderlying is only invokable for IDerivativeSecurity (Option|Future)"; } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class MarketHoursDatabase { /// /// String message saying: Future.Usa market type is no longer supported as we mapped each ticker to its actual exchange /// public static string FutureUsaMarketTypeNoLongerSupported = "Future.Usa market type is no longer supported as we mapped each ticker to its actual exchange. " + "Please find your specific market in the symbol-properties database."; /// /// Returns a string message saying it was impossible to locate exchange hours for the given key. It also /// mentiones the available keys /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ExchangeHoursNotFound(Securities.SecurityDatabaseKey key, IEnumerable availableKeys = null) { var keys = ""; if (availableKeys != null) { keys = " Available keys: " + string.Join(", ", availableKeys); } return $"Unable to locate exchange hours for {key}.{keys}"; } /// /// Returns a string message that suggests the given market based on the provided ticker /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string SuggestedMarketBasedOnTicker(string market) { return $"Suggested market based on the provided ticker 'Market.{market.ToUpperInvariant()}'."; } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class MarketHoursSegment { /// /// String message saying: Extended market open time must be less than or equal to market open time /// public static string InvalidExtendedMarketOpenTime = "Extended market open time must be less than or equal to market open time."; /// /// String message saying: Market close time must be after market open time /// public static string InvalidMarketCloseTime = "Market close time must be after market open time."; /// /// String message saying: Extended market close time must be greater than or equal to market close time /// public static string InvalidExtendedMarketCloseTime = "Extended market close time must be greater than or equal to market close time."; /// /// Parses a MarketHourSegment object into a string message containing basic information about it /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToString(Securities.MarketHoursSegment instance) { return $"{instance.State}: {instance.Start.ToStringInvariant(null)}-{instance.End.ToStringInvariant(null)}"; } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class RegisteredSecurityDataTypesProvider { /// /// Returns a string message saying two different types were detected trying to register the same type name. It also /// mentions the two different types /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string TwoDifferentTypesDetectedForTheSameTypeName(Type type, Type existingType) { return $"Two different types were detected trying to register the same type name: {existingType} - {type}"; } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class Security { /// /// String message saying: Security requires a valid SymbolProperties instance /// public static string ValidSymbolPropertiesInstanceRequired = "Security requires a valid SymbolProperties instance."; /// /// String message saying: symbolProperties.QuoteCurrency must match the quoteCurrency.Symbol /// public static string UnmatchingQuoteCurrencies = "symbolProperties.QuoteCurrency must match the quoteCurrency.Symbol"; /// /// String message saying: Security.SetLocalTimeKeeper(LocalTimeKeeper) must be called in order to use the LocalTime property /// public static string SetLocalTimeKeeperMustBeCalledBeforeUsingLocalTime = "Security.SetLocalTimeKeeper(LocalTimeKeeper) must be called in order to use the LocalTime property."; /// /// String message saying: Symbols must match /// public static string UnmatchingSymbols = "Symbols must match."; /// /// String message saying: ExchangeTimeZones must match /// public static string UnmatchingExchangeTimeZones = "ExchangeTimeZones must match."; } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class SecurityDatabaseKey { /// /// Returns a string message saying the specified and given key was not in the expected format /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string KeyNotInExpectedFormat(string key) { return $"The specified key was not in the expected format: {key}"; } /// /// Parses a SecurityDatabaseKey into a string message with basic information about it /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToString(Securities.SecurityDatabaseKey instance) { return Invariant($"{instance.SecurityType}-{instance.Market}-{instance.Symbol}"); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class SecurityDefinitionSymbolResolver { /// /// Returns a string message saying no security definitions data have been loaded from the given file /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string NoSecurityDefinitionsLoaded(string securitiesDefinitionKey) { return $"No security definitions data loaded from file: {securitiesDefinitionKey}"; } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class SecurityExchangeHours { /// /// Returns an error message when the next market open could not be located within two weeks. /// Includes additional guidance if the market is always open (e.g., crypto assets). /// public static string UnableToLocateNextMarketOpenInTwoWeeks(bool isMarketAlwaysOpen) { var message = "Unable to locate next market open within two weeks."; if (!isMarketAlwaysOpen) { return message; } message += " Market is always open for this asset, this can happen e.g. if using TimeRules AfterMarketOpen for a crypto asset. " + "An alternative would be TimeRules.At(), TimeRules.Every(), TimeRules.Midnight or TimeRules.Noon instead"; return message; } /// /// Returns an error message when the next market close could not be located within two weeks. /// Includes additional guidance if the market is always open (e.g., crypto assets). /// public static string UnableToLocateNextMarketCloseInTwoWeeks(bool isMarketAlwaysOpen) { var message = "Unable to locate next market close within two weeks."; if (!isMarketAlwaysOpen) { return message; } message += " Market is always open for this asset, this can happen e.g. if using TimeRules BeforeMarketClose for a crypto asset. " + "An alternative would be TimeRules.At(), TimeRules.Every(), TimeRules.Midnight or TimeRules.Noon instead"; return message; } /// /// Returns a string message saying it did not find last market open for the given local date time. It also mentions /// if the market is always open or not /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string LastMarketOpenNotFound(DateTime localDateTime, bool isMarketAlwaysOpen) { return $"Did not find last market open for {localDateTime}. IsMarketAlwaysOpen: {isMarketAlwaysOpen}"; } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class SecurityHolding { /// /// Parses the given SecurityHolding object into a string message containing basic information about it /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToString(Securities.SecurityHolding instance) { return Invariant($"{instance.Symbol.Value}: {instance.Quantity} @ {instance.AveragePrice}"); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class SecurityManager { /// /// Returns a string message saying the given symbol was not found in the user security list /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string SymbolNotFoundInSecurities(QuantConnect.Symbol symbol) { return Invariant($@"This asset symbol ({ symbol}) was not found in your security list. Please add this security or check it exists before using it with 'Securities.ContainsKey(""{ QuantConnect.SymbolCache.GetTicker(symbol)}"")'"); } /// /// Returns a string message saying the given symbol could not be overwritten /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string UnableToOverwriteSecurity(QuantConnect.Symbol symbol) { return Invariant($"Unable to overwrite existing Security: {symbol}"); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class SecurityPortfolioManager { /// /// Returns a string message saying Portfolio object is an adaptor for Security Manager and that to add a new asset /// the required data should added during initialization /// public static string DictionaryAddNotImplemented = "Portfolio object is an adaptor for Security Manager. To add a new asset add the required data during initialization."; /// /// Returns a string message saying the Portfolio object object is an adaptor for Security Manager and cannot be cleared /// public static string DictionaryClearNotImplemented = "Portfolio object is an adaptor for Security Manager and cannot be cleared."; /// /// Returns a string message saying the Portfolio object is an adaptor for Security Manager and objects cannot be removed /// public static string DictionaryRemoveNotImplemented = "Portfolio object is an adaptor for Security Manager and objects cannot be removed."; /// /// Returns a string message saying the AccountCurrency cannot be changed after adding a Security and that the method /// SetAccountCurrency() should be moved before AddSecurity() /// public static string CannotChangeAccountCurrencyAfterAddingSecurity = "Cannot change AccountCurrency after adding a Security. Please move SetAccountCurrency() before AddSecurity()."; /// /// Returns a string message saying the AccountCurrency cannot be changed after setting cash and that the method /// SetAccountCurrency() should be moved before SetCash() /// public static string CannotChangeAccountCurrencyAfterSettingCash = "Cannot change AccountCurrency after setting cash. Please move SetAccountCurrency() before SetCash()."; /// /// Returns a string message saying the AccountCurrency has already been set and that the new value for this property /// will be ignored /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string AccountCurrencyAlreadySet(Securities.CashBook cashBook, string newAccountCurrency) { return $"account currency has already been set to {cashBook.AccountCurrency}. Will ignore new value {newAccountCurrency}"; } /// /// Returns a string message saying the AccountCurrency is being set to the given account currency /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string SettingAccountCurrency(string accountCurrency) { return $"setting account currency to {accountCurrency}"; } /// /// Returns a string message saying the total margin information, this is, the total margin used as well as the /// margin remaining /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string TotalMarginInformation(decimal totalMarginUsed, decimal marginRemaining) { return Invariant($"Total margin information: TotalMarginUsed: {totalMarginUsed:F2}, MarginRemaining: {marginRemaining:F2}"); } /// /// Returns a string message saying the order request margin information, this is, the margin used and the margin remaining /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string OrderRequestMarginInformation(decimal marginUsed, decimal marginRemaining) { return Invariant($"Order request margin information: MarginUsed: {marginUsed:F2}, MarginRemaining: {marginRemaining:F2}"); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class SecurityService { /// /// Returns a string message saying the given Symbol could not be found in the Symbol Properties Database /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string SymbolNotFoundInSymbolPropertiesDatabase(QuantConnect.Symbol symbol) { return $"{symbol.SecurityType} '{symbol.Value}' symbol could not be found in the database for {symbol.ID.Market} market"; } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class SecurityTransactionManager { /// /// Returns a string message saying CancelOpenOrders operation is not allowed in Initialize or during warm up /// public static string CancelOpenOrdersNotAllowedOnInitializeOrWarmUp = "This operation is not allowed in Initialize or during warm up: CancelOpenOrders. Please move this code to the OnWarmupFinished() method."; /// /// Returns a string message saying the order was canceled by the CancelOpenOrders() at the given time /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string OrderCanceledByCancelOpenOrders(DateTime time) { return Invariant($"Canceled by CancelOpenOrders() at {time:o}"); } /// /// Returns a string message saying the ticket for the given order ID could not be localized /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string UnableToLocateOrderTicket(int orderId) { return Invariant($"Unable to locate ticket for order: {orderId}"); } /// /// Returns a string message saying the order did not fill within the given amount of seconds /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string OrderNotFilledWithinExpectedTime(TimeSpan fillTimeout) { return Invariant($"Order did not fill within {fillTimeout.TotalSeconds} seconds."); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class SymbolProperties { /// /// String message saying the SymbolProperties LotSize can not be less than or equal to 0 /// public static string InvalidLotSize = "SymbolProperties LotSize can not be less than or equal to 0"; /// /// String message saying the SymbolProperties PriceMagnifier can not be less than or equal to 0 /// public static string InvalidPriceMagnifier = "SymbolProprties PriceMagnifier can not be less than or equal to 0"; /// /// String message saying the SymbolProperties StrikeMultiplier can not be less than or equal to 0 /// public static string InvalidStrikeMultiplier = "SymbolProperties StrikeMultiplier can not be less than or equal to 0"; /// /// Parses a given SymbolProperties object into a string message /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToString(Securities.SymbolProperties instance) { var marketTicker = ","; var minimumOrderSize = marketTicker; var priceMagnifier = marketTicker; if (!string.IsNullOrEmpty(instance.MarketTicker)) { marketTicker = $",{instance.MarketTicker}"; } if (instance.MinimumOrderSize != null) { minimumOrderSize = Invariant($",{instance.MinimumOrderSize}"); } if (instance.PriceMagnifier != 1) { priceMagnifier = Invariant($",{instance.PriceMagnifier}"); } return Invariant($@"{instance.Description},{instance.QuoteCurrency},{instance.ContractMultiplier},{ instance.MinimumPriceVariation},{instance.LotSize}{marketTicker}{minimumOrderSize}{priceMagnifier}"); } } /// /// Provides user-facing messages for the class and its consumers or related classes /// public static class SymbolPropertiesDatabase { //public static string InvalidLotSize = "SymbolProperties LotSize can not be less than or equal to 0"; /// /// Returns a string saying a duplicated key was found while processing the given file /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string DuplicateKeyInFile(string file, Securities.SecurityDatabaseKey key) { return $"Encountered duplicate key while processing file: {file}. Key: {key}"; } /// /// Returns a string saying the given symbol properties file could not be localized /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string DatabaseFileNotFound(string file) { return $"Unable to locate symbol properties file: {file}"; } } } }