chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:02:50 +08:00
commit 0fc60fdcb1
5008 changed files with 910633 additions and 0 deletions
@@ -0,0 +1,93 @@
/*
* 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.
*/
namespace QuantConnect.Securities.CryptoFuture
{
/// <summary>
/// Binance-specific crypto future margin model that includes supplementary stable coin
/// currencies as alternative collateral for non-coin (USDⓈ-M) futures.
/// </summary>
/// <remarks>
/// EU/EEA users under MiCA Credits Trading Mode have BNFCR in their account.
/// When BNFCR is present, this model aggregates all supplementary collateral assets
/// using their walletBalance values converted to the primary collateral currency.
/// Non-EU accounts don't have BNFCR — the check is a no-op for them.
/// See: https://www.binance.com/en/support/faq/detail/0e857c392a2d47cebde0af762d9255ae
/// </remarks>
public class BinanceCryptoFutureMarginModel : CryptoFutureMarginModel
{
/// <summary>
/// Binance Futures Credits currency symbol, present in EU/EEA accounts under MiCA Credits Trading Mode.
/// </summary>
private const string BNFCRCurrency = "BNFCR";
/// <summary>
/// Creates a new instance
/// </summary>
/// <param name="leverage">The leverage to use, default 25x</param>
public BinanceCryptoFutureMarginModel(decimal leverage = 25)
: base(leverage)
{
}
/// <summary>
/// Gets the total collateral amount for a Binance crypto future, including supplementary
/// collateral assets for EU/EEA accounts in MiCA Credits Trading Mode.
/// For coin futures (e.g. BTCUSD), only the primary collateral (base currency) is used.
/// </summary>
/// <param name="portfolio">The algorithm's portfolio</param>
/// <param name="security">The crypto future security</param>
/// <param name="primaryCollateral">The primary collateral cash (e.g. USDT)</param>
/// <returns>Total collateral amount in terms of the primary collateral currency</returns>
protected override decimal GetTotalCollateralAmount(
SecurityPortfolioManager portfolio, Security security, Cash primaryCollateral)
{
// BNFCR presence means EU/EEA account in MiCA Credits Trading Mode.
// Non-EU accounts don't have BNFCR in CashBook — skip entirely.
var cashBook = portfolio.CashBook;
if (!cashBook.ContainsKey(BNFCRCurrency))
{
return base.GetTotalCollateralAmount(portfolio, security, primaryCollateral);
}
// Aggregate all collateral assets using walletBalance values.
// Binance controls which assets are in the account — we sum everything
// with a non-zero balance, converting to the primary collateral currency.
// Negative amounts (e.g. BNFCR fees) correctly reduce the total.
var total = 0m;
foreach (var kvp in cashBook)
{
var cash = kvp.Value;
if (cash.Amount == 0)
{
continue;
}
total += cashBook.Convert(cash.Amount, cash.Symbol, primaryCollateral.Symbol);
}
return total;
}
/// <summary>
/// When BNFCR is present (EU/MiCA mode), all USDⓈ-M futures share the same collateral
/// pool regardless of quote currency (USDT, USDC, etc.).
/// </summary>
protected override bool SharesCollateral(SecurityPortfolioManager portfolio, Cash collateralCurrency, Security otherCryptoFuture)
{
return portfolio.CashBook.ContainsKey(BNFCRCurrency) || base.SharesCollateral(portfolio, collateralCurrency, otherCryptoFuture);
}
}
}
@@ -0,0 +1,100 @@
/*
* 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 QuantConnect.Data.Market;
namespace QuantConnect.Securities.CryptoFuture
{
/// <summary>
/// The responsability of this model is to apply future funding rate cash flows to the portfolio based on open positions
/// </summary>
public class BinanceFutureMarginInterestRateModel : IMarginInterestRateModel
{
private DateTime _nextFundingRateApplication = DateTime.MaxValue;
/// <summary>
/// Apply margin interest rates to the portfolio
/// </summary>
/// <param name="marginInterestRateParameters">The parameters to use</param>
public void ApplyMarginInterestRate(MarginInterestRateParameters marginInterestRateParameters)
{
var security = marginInterestRateParameters.Security;
var time = marginInterestRateParameters.Time;
var cryptoFuture = (CryptoFuture)security;
if (!cryptoFuture.Invested)
{
// nothing to do
_nextFundingRateApplication = DateTime.MaxValue;
return;
}
else if (_nextFundingRateApplication == DateTime.MaxValue)
{
// we opened a new position
_nextFundingRateApplication = GetNextFundingRateApplication(time);
}
var marginInterest = cryptoFuture.Cache.GetData<MarginInterestRate>();
if(marginInterest == null)
{
return;
}
while(time >= _nextFundingRateApplication)
{
// When the funding rate is positive, the price of the perpetual contract is higher than the mark price,
// thus, traders who are long pay for short positions. Conversely, a negative funding rate indicates that perpetual
// prices are below the mark price, which means that short positions pay for longs.
// Funding Amount = Nominal Value of Positions * Funding Rate
var holdings = cryptoFuture.Holdings;
var positionValue = cryptoFuture.Holdings.GetQuantityValue(holdings.Quantity);
var funding = marginInterest.InterestRate * positionValue.Amount;
funding *= -1;
// '* -1' because:
// - we pay when 'funding' positive:
// long position & positive rate
// short position & negative rate
// - we ear when 'funding' negative:
// long position & negative rate
// short position & positive rate
positionValue.Cash.AddAmount(funding);
_nextFundingRateApplication = GetNextFundingRateApplication(_nextFundingRateApplication);
}
}
private static DateTime GetNextFundingRateApplication(DateTime currentTime)
{
if(currentTime.Hour >= 16)
{
// tomorrow 00:00
return currentTime.Date.AddDays(1);
}
else if (currentTime.Hour >= 8)
{
return currentTime.Date.AddHours(16);
}
else
{
return currentTime.Date.AddHours(8);
}
}
}
}
@@ -0,0 +1,25 @@
/*
* 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.
*
*/
namespace QuantConnect.Securities.CryptoFuture
{
/// <summary>
/// The responsibility of this model is to apply future funding rate cash flows to the portfolio based on open positions
/// </summary>
public class BybitFutureMarginInterestRateModel : BinanceFutureMarginInterestRateModel
{
}
}
@@ -0,0 +1,104 @@
/*
* 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 QuantConnect.Orders.Fees;
using QuantConnect.Orders.Fills;
using QuantConnect.Orders.Slippage;
namespace QuantConnect.Securities.CryptoFuture
{
/// <summary>
/// Crypto Future Security Object Implementation for Crypto Future Assets
/// </summary>
public class CryptoFuture : Security, IBaseCurrencySymbol
{
/// <summary>
/// Gets the currency acquired by going long this currency pair
/// </summary>
/// <remarks>
/// For example, the EUR/USD has a base currency of the euro, and as a result
/// of going long the EUR/USD a trader is acquiring euros in exchange for US dollars
/// </remarks>
public Cash BaseCurrency { get; protected set; }
/// <summary>
/// Constructor for the Crypto Future security
/// </summary>
/// <param name="symbol">The symbol</param>
/// <param name="exchangeHours">Defines the hours this exchange is open</param>
/// <param name="quoteCurrency">The cash object that represent the quote currency</param>
/// <param name="baseCurrency">The cash object that represent the base currency</param>
/// <param name="symbolProperties">The symbol properties for this security</param>
/// <param name="currencyConverter">Currency converter used to convert <see cref="CashAmount"/>
/// instances into units of the account currency</param>
/// <param name="registeredTypes">Provides all data types registered in the algorithm</param>
/// <param name="cache">The security cache</param>
public CryptoFuture(Symbol symbol,
SecurityExchangeHours exchangeHours,
Cash quoteCurrency,
Cash baseCurrency,
SymbolProperties symbolProperties,
ICurrencyConverter currencyConverter,
IRegisteredSecurityDataTypesProvider registeredTypes,
SecurityCache cache)
: base(symbol,
quoteCurrency,
symbolProperties,
new CryptoFutureExchange(exchangeHours),
cache,
new SecurityPortfolioModel(),
new ImmediateFillModel(),
IsCryptoCoinFuture(quoteCurrency.Symbol) ? new BinanceCoinFuturesFeeModel() : new BinanceFuturesFeeModel(),
NullSlippageModel.Instance,
new ImmediateSettlementModel(),
Securities.VolatilityModel.Null,
new CryptoFutureMarginModel(),
new SecurityDataFilter(),
new SecurityPriceVariationModel(),
currencyConverter,
registeredTypes,
// only applies for perpetual futures
symbol.ID.Date == SecurityIdentifier.DefaultDate ? new BinanceFutureMarginInterestRateModel() : Securities.MarginInterestRateModel.Null
)
{
BaseCurrency = baseCurrency;
Holdings = new CryptoFutureHolding(this, currencyConverter);
}
/// <summary>
/// Checks whether the security is a crypto coin future
/// </summary>
/// <returns>True if the security is a crypto coin future</returns>
public bool IsCryptoCoinFuture()
{
return IsCryptoCoinFuture(QuoteCurrency.Symbol);
}
/// <summary>
/// Checks whether the security is a crypto coin future
/// </summary>
/// <param name="quoteCurrency">The security quote currency</param>
/// <returns>True if the security is a crypto coin future</returns>
private static bool IsCryptoCoinFuture(string quoteCurrency)
{
return quoteCurrency != "USDT" && quoteCurrency != "BUSD" && quoteCurrency != "USDC";
}
/// <summary>
/// Returns the securities symbol
/// </summary>
public static implicit operator Symbol(CryptoFuture security) => security.Symbol;
}
}
@@ -0,0 +1,43 @@
/*
* 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.
*/
namespace QuantConnect.Securities.CryptoFuture
{
/// <summary>
/// Crypto future exchange class - information and helper tools for Crypto future exchange properties
/// </summary>
/// <seealso cref="SecurityExchange"/>
public class CryptoFutureExchange : SecurityExchange
{
/// <summary>
/// Initializes a new instance of the <see cref="CryptoFutureExchange"/> class using market hours
/// derived from the market-hours-database for the Crypto future market
/// </summary>
public CryptoFutureExchange(string market)
: base(MarketHoursDatabase.FromDataFolder().GetExchangeHours(market, null, SecurityType.CryptoFuture))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CryptoFutureExchange"/> class using the specified
/// exchange hours to determine open/close times
/// </summary>
/// <param name="exchangeHours">Contains the weekly exchange schedule plus holidays</param>
public CryptoFutureExchange(SecurityExchangeHours exchangeHours)
: base(exchangeHours)
{
}
}
}
@@ -0,0 +1,75 @@
/*
* 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.
*/
namespace QuantConnect.Securities.CryptoFuture
{
/// <summary>
/// Crypto Future holdings implementation of the base securities class
/// </summary>
/// <seealso cref="SecurityHolding"/>
public class CryptoFutureHolding : SecurityHolding
{
/// <summary>
/// Crypto Future Holding Class constructor
/// </summary>
/// <param name="security">The crypto future security being held</param>
/// <param name="currencyConverter">A currency converter instance</param>
public CryptoFutureHolding(Security security, ICurrencyConverter currencyConverter)
: base(security, currencyConverter)
{
}
/// <summary>
/// Gets the total value of the specified <paramref name="quantity"/> of shares of this security
/// in the account currency
/// </summary>
/// <param name="quantity">The quantity of shares</param>
/// <param name="price">The current price</param>
/// <returns>The value of the quantity of shares in the account currency</returns>
public override ConvertibleCashAmount GetQuantityValue(decimal quantity, decimal price)
{
if (Symbol.ID.Market == Market.DYDX)
{
// common math quantity * quote price
return base.GetQuantityValue(quantity, price);
}
var cryptoFuture = (CryptoFuture)Security;
Cash cash;
decimal notionalPositionValue;
// We could check quote currency or the contract multiplier being 1
if (!cryptoFuture.IsCryptoCoinFuture())
{
// https://www.binance.com/en/support/faq/how-to-calculate-cost-required-to-open-a-position-in-perpetual-futures-contracts-87fa7ee33b574f7084d42bd2ce2e463b
// example BTCUSDT: (9,253.30 * 1 BTC) = 9,253.3 USDT
notionalPositionValue = price * quantity * cryptoFuture.SymbolProperties.ContractMultiplier;
// USDT is the QUOTE currency we will need to convert it into account currency
cash = cryptoFuture.QuoteCurrency;
}
else
{
// https://www.binance.com/en/support/faq/leverage-and-margin-in-coin-margined-futures-contracts-be2c7d9d95b04a7e8044ed02dd7dfe5c
// example BTCUSD: [ (10*100 USD) / 9,800 USD ] = 0.10204 BTC
notionalPositionValue = quantity * cryptoFuture.SymbolProperties.ContractMultiplier / price;
// BTC is the BASE currency we will need to convert it into account currency
cash = cryptoFuture.BaseCurrency;
}
return new ConvertibleCashAmount(notionalPositionValue, cash);
}
}
}
@@ -0,0 +1,184 @@
/*
* 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.Linq;
using QuantConnect.Orders;
namespace QuantConnect.Securities.CryptoFuture
{
/// <summary>
/// The crypto future margin model which supports both Coin and USDT futures
/// </summary>
public class CryptoFutureMarginModel : SecurityMarginModel
{
/// <summary>
/// Creates a new instance
/// </summary>
/// <param name="leverage">The leverage to use, used on initial margin requirements, default 25x</param>
/// <param name="maintenanceMarginRate">The maintenance margin rate, default 5%</param>
/// <param name="maintenanceAmount">The maintenance amount which will reduce maintenance margin requirements, default 0</param>
[Obsolete("This constructor is deprecated, please use the overload without maintenanceMarginRate and maintenanceAmount parameters.")]
public CryptoFutureMarginModel(decimal leverage, decimal maintenanceMarginRate = 0.05m, decimal maintenanceAmount = 0)
: base(leverage, 0)
{
}
/// <summary>
/// Creates a new instance
/// </summary>
/// <param name="leverage">The leverage to use, used on initial margin requirements, default 25x</param>
public CryptoFutureMarginModel(decimal leverage = 25)
: base(leverage, 0)
{
}
/// <summary>
/// Gets the margin currently alloted to the specified holding.
/// </summary>
/// <param name="parameters">An object containing the security</param>
/// <returns>The maintenance margin required for the option</returns>
public override MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters)
{
return new MaintenanceMargin(GetInitialMarginRequirement(new InitialMarginParameters(parameters.Security, parameters.Quantity)));
}
/// <summary>
/// The margin that must be held in order to increase the position by the provided quantity
/// </summary>
/// <param name="parameters">An object containing the security and quantity of shares</param>
/// <returns>The initial margin required for the option (i.e. the equity required to enter a position for this option)</returns>
public override InitialMargin GetInitialMarginRequirement(InitialMarginParameters parameters)
{
var security = parameters.Security;
var quantity = parameters.Quantity;
if (security?.GetLastData() == null || quantity == 0m)
{
return InitialMargin.Zero;
}
var positionValue = security.Holdings.GetQuantityValue(quantity, security.Price);
var marginRequirementInCollateral = Math.Abs(positionValue.Amount) / GetLeverage(security);
return new InitialMargin(marginRequirementInCollateral * positionValue.Cash.ConversionRate);
}
/// <summary>
/// Gets the margin cash available for a trade
/// </summary>
/// <param name="portfolio">The algorithm's portfolio</param>
/// <param name="security">The security to be traded</param>
/// <param name="direction">The direction of the trade</param>
/// <returns>The margin available for the trade</returns>
/// <remarks>What we do specially here is that instead of using the total portfolio value as potential margin remaining we only consider the collateral currency</remarks>
protected override decimal GetMarginRemaining(SecurityPortfolioManager portfolio, Security security, OrderDirection direction)
{
var collateralCurrency = GetCollateralCash(security);
var totalCollateralCurrency = GetTotalCollateralAmount(portfolio, security, collateralCurrency);
var result = totalCollateralCurrency;
foreach (var kvp in portfolio.Where(holdings => holdings.Value.Invested && holdings.Value.Type == SecurityType.CryptoFuture && holdings.Value.Symbol != security.Symbol))
{
var otherCryptoFuture = portfolio.Securities[kvp.Key];
// check if we share the collateral
if (SharesCollateral(portfolio, collateralCurrency, otherCryptoFuture))
{
// we reduce the available collateral based on total usage of all other positions too
result -= otherCryptoFuture.BuyingPowerModel.GetMaintenanceMargin(MaintenanceMarginParameters.ForCurrentHoldings(otherCryptoFuture));
}
}
if (direction != OrderDirection.Hold)
{
var holdings = security.Holdings;
//If the order is in the same direction as holdings, our remaining cash is our cash
//In the opposite direction, our remaining cash is 2 x current value of assets + our cash
if (holdings.IsLong)
{
switch (direction)
{
case OrderDirection.Sell:
result +=
// portion of margin to close the existing position
this.GetMaintenanceMargin(security) +
// portion of margin to open the new position
this.GetInitialMarginRequirement(security, security.Holdings.AbsoluteQuantity);
break;
}
}
else if (holdings.IsShort)
{
switch (direction)
{
case OrderDirection.Buy:
result +=
// portion of margin to close the existing position
this.GetMaintenanceMargin(security) +
// portion of margin to open the new position
this.GetInitialMarginRequirement(security, security.Holdings.AbsoluteQuantity);
break;
}
}
}
result -= totalCollateralCurrency * RequiredFreeBuyingPowerPercent;
// convert into account currency
result *= collateralCurrency.ConversionRate;
return result < 0 ? 0 : result;
}
/// <summary>
/// Determines whether the given security shares collateral with another crypto future.
/// </summary>
/// <param name="portfolio">The algorithm's portfolio</param>
/// <param name="collateralCurrency">The collateral cash for the current security</param>
/// <param name="otherCryptoFuture">The other crypto future security to check</param>
/// <returns>True if both securities share the same collateral</returns>
protected virtual bool SharesCollateral(SecurityPortfolioManager portfolio, Cash collateralCurrency, Security otherCryptoFuture)
{
return collateralCurrency == GetCollateralCash(otherCryptoFuture);
}
/// <summary>
/// Helper method to determine what's the collateral currency for the given crypto future
/// </summary>
private static Cash GetCollateralCash(Security security)
{
var cryptoFuture = (CryptoFuture)security;
var collateralCurrency = cryptoFuture.BaseCurrency;
if (!cryptoFuture.IsCryptoCoinFuture())
{
collateralCurrency = cryptoFuture.QuoteCurrency;
}
return collateralCurrency;
}
/// <summary>
/// Gets the total collateral amount for the given crypto future position.
/// The base implementation returns only the primary collateral amount.
/// Override in subclasses to include supplementary collateral currencies.
/// </summary>
/// <param name="portfolio">The algorithm's portfolio</param>
/// <param name="security">The crypto future security</param>
/// <param name="primaryCollateral">The primary collateral cash (e.g. USDT for non-coin futures, BTC for coin futures)</param>
/// <returns>Total collateral amount in terms of the primary collateral currency</returns>
protected virtual decimal GetTotalCollateralAmount(SecurityPortfolioManager portfolio, Security security, Cash primaryCollateral)
{
return primaryCollateral.Amount;
}
}
}
@@ -0,0 +1,25 @@
/*
* 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.
*
*/
namespace QuantConnect.Securities.CryptoFuture
{
/// <summary>
/// The responsibility of this model is to apply future funding rate cash flows to the portfolio based on open positions
/// </summary>
public class dYdXFutureMarginInterestRateModel : BinanceFutureMarginInterestRateModel
{
}
}