/*
* 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}";
}
}
}
}