Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions Common/Currencies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,38 @@ public static class Currencies
{ Market.DYDX , _stableCoinsWithoutPairsdYdX}
};

private static readonly HashSet<string> _dollarStablePairs = ["USDT", "USDC", USD];

/// <summary>
/// Checks whether or not certain symbol is a StableCoin without pair in a given market
/// </summary>
/// <param name="accountCurrency">The account currency</param>
/// <param name="cashSymbol">The target cash symbol</param>
/// <param name="market">The market in which we want to search for that StableCoin</param>
/// <returns>True if the given symbol is a StableCoin without pair in the given market</returns>
public static bool IsStableCoinWithoutPair(string accountCurrency, string cashSymbol, string market)
{
IEnumerable<string> _targets;
if (_dollarStablePairs.Contains(accountCurrency))
{
// let's be polite and handle USDT/USDC/USD, this is internal
_targets = _dollarStablePairs.Where(x => x != cashSymbol).SelectMany(x => new[] { x + cashSymbol, cashSymbol + x }).ToArray();
}
else
{
_targets = [accountCurrency + cashSymbol, cashSymbol + accountCurrency];
}

foreach (var target in _targets)
{
if (IsStableCoinWithoutPair(target, market))
{
return true;
}
}
return false;
}

/// <summary>
/// Checks whether or not certain symbol is a StableCoin without pair in a given market
/// </summary>
Expand Down
21 changes: 9 additions & 12 deletions Common/Securities/Cash.cs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,15 @@ public List<SubscriptionDataConfig> EnsureCurrencyDataFeed(SecurityManager secur
.Concat(cryptoEntries)
.ToList();

// Special case for crypto markets without direct pairs (They wont be found by the above)
// This allows us to add cash for "StableCoins" that are 1-1 with our account currency without needing a conversion security.
// Check out the StableCoinsWithoutPairs static var for those that are missing their 1-1 conversion pairs
if (marketMap.TryGetValue(SecurityType.Crypto, out var market) && Currencies.IsStableCoinWithoutPair(accountCurrency, Symbol, market))
{
CurrencyConversion = ConstantCurrencyConversion.Identity(accountCurrency, Symbol);
return null;
}

if (!potentialEntries.Any(x =>
Symbol == x.Key.Symbol.Substring(0, x.Key.Symbol.Length - x.Value.QuoteCurrency.Length) ||
Symbol == x.Value.QuoteCurrency))
Expand All @@ -285,18 +294,6 @@ public List<SubscriptionDataConfig> EnsureCurrencyDataFeed(SecurityManager secur
return null;
}

// Special case for crypto markets without direct pairs (They wont be found by the above)
// This allows us to add cash for "StableCoins" that are 1-1 with our account currency without needing a conversion security.
// Check out the StableCoinsWithoutPairs static var for those that are missing their 1-1 conversion pairs
if (marketMap.TryGetValue(SecurityType.Crypto, out var market)
&&
(Currencies.IsStableCoinWithoutPair(Symbol + accountCurrency, market)
|| Currencies.IsStableCoinWithoutPair(accountCurrency + Symbol, market)))
{
CurrencyConversion = ConstantCurrencyConversion.Identity(accountCurrency, Symbol);
return null;
}

var requiredSecurities = new List<SubscriptionDataConfig>();

var potentials = potentialEntries
Expand Down
2 changes: 1 addition & 1 deletion Common/Securities/CryptoFuture/CryptoFuture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public bool IsCryptoCoinFuture()
/// <returns>True if the security is a crypto coin future</returns>
private static bool IsCryptoCoinFuture(string quoteCurrency)
{
return quoteCurrency != "USDT" && quoteCurrency != "BUSD";
return quoteCurrency != "USDT" && quoteCurrency != "BUSD" && quoteCurrency != "USDC";
}

/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion Tests/Common/Securities/CashTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ public void EnsureCurrencyDataFeedDoesNothingWithUnsupportedCurrency()
public void CryptoStableCoinMappingIsCorrect(IBrokerageModel brokerageModel, string accountCurrency, string stableCoin, bool shouldThrow, Symbol[] expectedConversionSymbols)
{
var cashBook = new CashBook() {AccountCurrency = accountCurrency};
var cash = new Cash(stableCoin, 10m, 1m);
var cash = new Cash(stableCoin, 10m, 0);
cashBook.Add(cash.Symbol, cash);

var subscriptions = new SubscriptionManager(NullTimeKeeper.Instance);
Expand Down Expand Up @@ -716,6 +716,9 @@ private static TimeKeeper TimeKeeper

// *** Binance ***
// USDC Cases
new object[] { new BinanceBrokerageModel(), "USDT", "BNFCR", false, null },
new object[] { new BinanceBrokerageModel(), "USDC", "BNFCR", false, null },
new object[] { new BinanceBrokerageModel(), Currencies.USD, "BNFCR", false, null },
new object[] { new BinanceBrokerageModel(), Currencies.USD, "USDC", false, null }, // No USDCUSD, but does not throw! Conversion 1-1
new object[] { new BinanceBrokerageModel(), Currencies.EUR, "USDC", false, new[] { Symbol.Create("EURUSDC", SecurityType.Crypto, Market.Binance) } },
new object[] { new BinanceBrokerageModel(), Currencies.GBP, "USDC", false, new[] { Symbol.Create("ADAUSDC", SecurityType.Crypto, Market.Binance), Symbol.Create("ADAGBP", SecurityType.Crypto, Market.Binance) } }, // No USDCGBP, but indirect conversion exists
Expand Down
Loading