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
+87
View File
@@ -0,0 +1,87 @@
/*
* 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.Securities;
using QuantConnect.Securities.Crypto;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Represents the fee model specific to Alpaca trading platform.
/// </summary>
/// <remarks>This class inherits from <see cref="FeeModel"/> and provides the fee structure for Alpaca trades.
/// It implements the <see cref="IFeeModel"/> interface and should be used for calculating fees on the Alpaca platform.</remarks>
public class AlpacaFeeModel : FeeModel
{
/// <summary>
/// The fee percentage for a maker transaction in cryptocurrency.
/// </summary>
/// <see href="https://docs.alpaca.markets/docs/crypto-fees"/>
public const decimal MakerCryptoFee = 0.0015m;
/// <summary>
/// The fee percentage for a taker transaction in cryptocurrency.
/// </summary>
public const decimal TakerCryptoFee = 0.0025m;
/// <summary>
/// Gets the order fee associated with the specified order.
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in a <see cref="CashAmount"/> instance</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var security = parameters.Security;
if (security.Symbol.ID.SecurityType == SecurityType.Crypto)
{
var order = parameters.Order;
var fee = GetFee(order, MakerCryptoFee, TakerCryptoFee);
CashAmount cashAmount;
Crypto.DecomposeCurrencyPair(security.Symbol, security.SymbolProperties, out var baseCurrency, out var quoteCurrency);
if (order.Direction == OrderDirection.Buy)
{
// base currency, deducted from what we bought
cashAmount = new CashAmount(order.AbsoluteQuantity * fee, baseCurrency);
}
else
{
// quote currency
var positionValue = order.AbsoluteQuantity * security.Price;
cashAmount = new CashAmount(positionValue * fee, quoteCurrency);
}
return new OrderFee(cashAmount);
}
return new OrderFee(new CashAmount(0, Currencies.USD));
}
/// <summary>
/// Calculates the fee for a given order based on whether it is a maker or taker order.
/// </summary>
/// <param name="order">The order for which the fee is being calculated.</param>
/// <param name="makerFee">The fee percentage for maker orders.</param>
/// <param name="takerFee">The fee percentage for taker orders.</param>
/// <returns>The calculated fee for the given order.</returns>
private static decimal GetFee(Order order, decimal makerFee, decimal takerFee)
{
if (order.Type == OrderType.Limit && !order.IsMarketable)
{
return makerFee;
}
return takerFee;
}
}
}
+161
View File
@@ -0,0 +1,161 @@
/*
* 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 QuantConnect.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models order fees that alpha stream clients pay/receive
/// </summary>
public class AlphaStreamsFeeModel : FeeModel
{
private readonly Dictionary<string, EquityFee> _equityFee =
new Dictionary<string, EquityFee> {
{ Market.USA, new EquityFee("USD", feePerShare: 0.005m, minimumFee: 1, maximumFeeRate: 0.005m) }
};
private readonly IDictionary<SecurityType, decimal> _feeRates = new Dictionary<SecurityType, decimal>
{
// Commission
{SecurityType.Forex, 0.000002m},
// Commission plus clearing fee
{SecurityType.Future, 0.4m + 0.1m},
{SecurityType.FutureOption, 0.4m + 0.1m},
{SecurityType.Option, 0.4m + 0.1m},
{SecurityType.IndexOption, 0.4m + 0.1m},
{SecurityType.Cfd, 0m}
};
private const decimal _makerFee = 0.001m;
private const decimal _takerFee = 0.002m;
/// <summary>
/// Gets the order fee associated with the specified order. This returns the cost
/// of the transaction in the account currency
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in units of the account currency</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var order = parameters.Order;
var security = parameters.Security;
// Option exercise is free of charge
if (order.Type == OrderType.OptionExercise)
{
return OrderFee.Zero;
}
var market = security.Symbol.ID.Market;
decimal feeRate;
switch (security.Type)
{
case SecurityType.Option:
case SecurityType.Future:
case SecurityType.FutureOption:
case SecurityType.Cfd:
_feeRates.TryGetValue(security.Type, out feeRate);
return new OrderFee(new CashAmount(feeRate * order.AbsoluteQuantity, Currencies.USD));
case SecurityType.Forex:
_feeRates.TryGetValue(security.Type, out feeRate);
return new OrderFee(new CashAmount(feeRate * Math.Abs(order.GetValue(security)), Currencies.USD));
case SecurityType.Crypto:
decimal fee = _takerFee;
var props = order.Properties as BitfinexOrderProperties;
if (order.Type == OrderType.Limit &&
props?.Hidden != true &&
(props?.PostOnly == true || !order.IsMarketable))
{
// limit order posted to the order book
fee = _makerFee;
}
// get order value in quote currency
var unitPrice = order.Direction == OrderDirection.Buy ? security.AskPrice : security.BidPrice;
if (order.Type == OrderType.Limit)
{
// limit order posted to the order book
unitPrice = ((LimitOrder)order).LimitPrice;
}
unitPrice *= security.SymbolProperties.ContractMultiplier;
// apply fee factor, currently we do not model 30-day volume, so we use the first tier
return new OrderFee(new CashAmount(
unitPrice * order.AbsoluteQuantity * fee,
security.QuoteCurrency.Symbol));
// Use the IB fee model
case SecurityType.Equity:
EquityFee equityFee;
if (!_equityFee.TryGetValue(market, out equityFee))
{
throw new KeyNotFoundException(Messages.AlphaStreamsFeeModel.UnexpectedEquityMarket(market));
}
var tradeValue = Math.Abs(order.GetValue(security));
//Per share fees
var tradeFee = equityFee.FeePerShare * order.AbsoluteQuantity;
//Maximum Per Order: equityFee.MaximumFeeRate
//Minimum per order. $equityFee.MinimumFee
var maximumPerOrder = equityFee.MaximumFeeRate * tradeValue;
if (tradeFee < equityFee.MinimumFee)
{
tradeFee = equityFee.MinimumFee;
}
else if (tradeFee > maximumPerOrder)
{
tradeFee = maximumPerOrder;
}
return new OrderFee(new CashAmount(Math.Abs(tradeFee), equityFee.Currency));
default:
// unsupported security type
throw new ArgumentException(Messages.FeeModel.UnsupportedSecurityType(security));
}
}
/// <summary>
/// Helper class to handle Equity fees
/// </summary>
private class EquityFee
{
public string Currency { get; }
public decimal FeePerShare { get; }
public decimal MinimumFee { get; }
public decimal MaximumFeeRate { get; }
public EquityFee(string currency,
decimal feePerShare,
decimal minimumFee,
decimal maximumFeeRate)
{
Currency = currency;
FeePerShare = feePerShare;
MinimumFee = minimumFee;
MaximumFeeRate = maximumFeeRate;
}
}
}
}
+48
View File
@@ -0,0 +1,48 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models Axos order fees
/// </summary>
public class AxosFeeModel: IFeeModel
{
private readonly decimal _feesPerShare;
/// <summary>
/// Creates a new instance
/// </summary>
/// <param name="feesPerShare">The fees per share to apply</param>
/// <remarks>Default value is $0.0015 per share</remarks>
public AxosFeeModel(decimal? feesPerShare = null)
{
_feesPerShare = feesPerShare ?? 0.0035m;
}
/// <summary>
/// Get the fee for this order in quote currency
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in quote currency</returns>
public OrderFee GetOrderFee(OrderFeeParameters parameters)
{
return new OrderFee(new CashAmount(_feesPerShare * parameters.Order.AbsoluteQuantity, Currencies.USD));
}
}
}
@@ -0,0 +1,45 @@
/*
* 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.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models Binance Coin Futures order fees
/// </summary>
public class BinanceCoinFuturesFeeModel : BinanceFeeModel
{
/// <summary>
/// Tier 1 maker fees
/// https://www.binance.com/en/fee/deliveryFee
/// </summary>
public new const decimal MakerTier1Fee = 0.0001m;
/// <summary>
/// Tier 1 taker fees
/// https://www.binance.com/en/fee/deliveryFee
/// </summary>
public new const decimal TakerTier1Fee = 0.0005m;
/// <summary>
/// Creates Binance Coin Futures fee model setting fees values
/// </summary>
/// <param name="mFee">Maker fee value</param>
/// <param name="tFee">Taker fee value</param>
public BinanceCoinFuturesFeeModel(decimal mFee = MakerTier1Fee, decimal tFee = TakerTier1Fee)
: base(mFee, tFee)
{
}
}
}
+120
View File
@@ -0,0 +1,120 @@
/*
* 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.Util;
using QuantConnect.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models Binance order fees
/// </summary>
public class BinanceFeeModel : FeeModel
{
/// <summary>
/// Tier 1 maker fees
/// https://www.binance.com/en/fee/schedule
/// </summary>
public const decimal MakerTier1Fee = 0.001m;
/// <summary>
/// Tier 1 taker fees
/// https://www.binance.com/en/fee/schedule
/// </summary>
public const decimal TakerTier1Fee = 0.001m;
private readonly decimal _makerFee;
private readonly decimal _takerFee;
/// <summary>
/// Creates Binance fee model setting fees values
/// </summary>
/// <param name="mFee">Maker fee value</param>
/// <param name="tFee">Taker fee value</param>
public BinanceFeeModel(decimal mFee = MakerTier1Fee, decimal tFee = TakerTier1Fee)
{
_makerFee = mFee;
_takerFee = tFee;
}
/// <summary>
/// Get the fee for this order in quote currency
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object containing the security and order</param>
/// <returns>The cost of the order in quote currency</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var security = parameters.Security;
var order = parameters.Order;
var fee = GetFee(order);
if(security.Symbol.ID.SecurityType == SecurityType.CryptoFuture)
{
var positionValue = security.Holdings.GetQuantityValue(order.AbsoluteQuantity, security.Price);
return new OrderFee(new CashAmount(positionValue.Amount * fee, positionValue.Cash.Symbol));
}
if (order.Direction == OrderDirection.Buy)
{
// fees taken in the received currency
CurrencyPairUtil.DecomposeCurrencyPair(order.Symbol, out var baseCurrency, out _);
return new OrderFee(new CashAmount(order.AbsoluteQuantity * fee, baseCurrency));
}
// get order value in quote currency
var unitPrice = order.Direction == OrderDirection.Buy ? security.AskPrice : security.BidPrice;
if (order.Type == OrderType.Limit)
{
// limit order posted to the order book
unitPrice = ((LimitOrder)order).LimitPrice;
}
unitPrice *= security.SymbolProperties.ContractMultiplier;
return new OrderFee(new CashAmount(
unitPrice * order.AbsoluteQuantity * fee,
security.QuoteCurrency.Symbol));
}
/// <summary>
/// Gets the fee factor for the given order
/// </summary>
/// <param name="order">The order to get the fee factor for</param>
/// <returns>The fee factor for the given order</returns>
protected virtual decimal GetFee(Order order)
{
return GetFee(order, _makerFee, _takerFee);
}
/// <summary>
/// Gets the fee factor for the given order taking into account the maker and the taker fee
/// </summary>
protected static decimal GetFee(Order order, decimal makerFee, decimal takerFee)
{
// apply fee factor, currently we do not model 30-day volume, so we use the first tier
var fee = takerFee;
var props = order.Properties as BinanceOrderProperties;
if (order.Type == OrderType.Limit && ((props != null && props.PostOnly) || !order.IsMarketable))
{
// limit order posted to the order book
fee = makerFee;
}
return fee;
}
}
}
@@ -0,0 +1,88 @@
/*
* 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.Util;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models Binance Futures order fees
/// </summary>
public class BinanceFuturesFeeModel : BinanceFeeModel
{
/// <summary>
/// Tier 1 USDT maker fees
/// https://www.binance.com/en/fee/futureFee
/// </summary>
public const decimal MakerTier1USDTFee = 0.0002m;
/// <summary>
/// Tier 1 USDT taker fees
/// https://www.binance.com/en/fee/futureFee
/// </summary>
public const decimal TakerTier1USDTFee = 0.0004m;
/// <summary>
/// Tier 1 BUSD maker fees
/// https://www.binance.com/en/fee/futureFee
/// </summary>
public const decimal MakerTier1BUSDFee = 0.00012m;
/// <summary>
/// Tier 1 BUSD taker fees
/// https://www.binance.com/en/fee/futureFee
/// </summary>
public const decimal TakerTier1BUSDFee = 0.00036m;
private decimal _makerUsdtFee;
private decimal _takerUsdtFee;
private decimal _makerBusdFee;
private decimal _takerBusdFee;
/// <summary>
/// Creates Binance Futures fee model setting fees values
/// </summary>
/// <param name="mUsdtFee">Maker fee value for USDT pair contracts</param>
/// <param name="tUsdtFee">Taker fee value for USDT pair contracts</param>
/// <param name="mBusdFee">Maker fee value for BUSD pair contracts</param>
/// <param name="tBusdFee">Taker fee value for BUSD pair contracts</param>
public BinanceFuturesFeeModel(decimal mUsdtFee = MakerTier1USDTFee, decimal tUsdtFee = TakerTier1USDTFee,
decimal mBusdFee = MakerTier1BUSDFee, decimal tBusdFee = TakerTier1BUSDFee)
: base(-1, -1)
{
_makerUsdtFee = mUsdtFee;
_takerUsdtFee = tUsdtFee;
_makerBusdFee = mBusdFee;
_takerBusdFee = tBusdFee;
}
/// <summary>
/// Gets the fee for the given order
/// </summary>
protected override decimal GetFee(Order order)
{
CurrencyPairUtil.DecomposeCurrencyPair(order.Symbol, out var _, out var quoteCurrency);
var makerFee = _makerUsdtFee;
var takerFee = _takerUsdtFee;
if (quoteCurrency == "BUSD")
{
makerFee = _makerBusdFee;
takerFee = _takerBusdFee;
}
return GetFee(order, makerFee, takerFee);
}
}
}
+84
View File
@@ -0,0 +1,84 @@
/*
* 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.Util;
using QuantConnect.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models Bitfinex order fees
/// </summary>
public class BitfinexFeeModel : FeeModel
{
/// <summary>
/// Tier 1 maker fees
/// Maker fees are paid when you add liquidity to our order book by placing a limit order under the ticker price for buy and above the ticker price for sell.
/// https://www.bitfinex.com/fees
/// </summary>
public const decimal MakerFee = 0.001m;
/// <summary>
/// Tier 1 taker fees
/// Taker fees are paid when you remove liquidity from our order book by placing any order that is executed against an order of the order book.
/// Note: If you place a hidden order, you will always pay the taker fee. If you place a limit order that hits a hidden order, you will always pay the maker fee.
/// https://www.bitfinex.com/fees
/// </summary>
public const decimal TakerFee = 0.002m;
/// <summary>
/// Get the fee for this order in quote currency
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in quote currency</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var order = parameters.Order;
var security = parameters.Security;
// apply fee factor, currently we do not model 30-day volume, so we use the first tier
var fee = TakerFee;
var props = order.Properties as BitfinexOrderProperties;
if (order.Type == OrderType.Limit &&
props?.Hidden != true &&
(props?.PostOnly == true || !order.IsMarketable))
{
// limit order posted to the order book
fee = MakerFee;
}
if (order.Direction == OrderDirection.Buy)
{
// fees taken in the received currency
CurrencyPairUtil.DecomposeCurrencyPair(order.Symbol, out var baseCurrency, out _);
return new OrderFee(new CashAmount(order.AbsoluteQuantity * fee, baseCurrency));
}
// get order value in quote currency
var unitPrice = order.Direction == OrderDirection.Buy ? security.AskPrice : security.BidPrice;
if (order.Type == OrderType.Limit)
{
// limit order posted to the order book
unitPrice = ((LimitOrder)order).LimitPrice;
}
unitPrice *= security.SymbolProperties.ContractMultiplier;
return new OrderFee(new CashAmount(
unitPrice * order.AbsoluteQuantity * fee,
security.QuoteCurrency.Symbol));
}
}
}
+117
View File
@@ -0,0 +1,117 @@
/*
* 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.Securities;
using QuantConnect.Util;
namespace QuantConnect.Orders.Fees;
/// <summary>
/// Bybit fee model implementation
/// </summary>
public class BybitFeeModel : FeeModel
{
/// <summary>
/// Tier 1 maker fees
/// https://learn.bybit.com/bybit-guide/bybit-trading-fees/
/// </summary>
public const decimal MakerNonVIPFee = 0.001m;
/// <summary>
/// Tier 1 taker fees
/// https://learn.bybit.com/bybit-guide/bybit-trading-fees/
/// </summary>
public const decimal TakerNonVIPFee = 0.001m;
private readonly decimal _makerFee;
private readonly decimal _takerFee;
/// <summary>
/// Creates Binance fee model setting fees values
/// </summary>
/// <param name="mFee">Maker fee value</param>
/// <param name="tFee">Taker fee value</param>
public BybitFeeModel(decimal mFee = MakerNonVIPFee, decimal tFee = TakerNonVIPFee)
{
_makerFee = mFee;
_takerFee = tFee;
}
/// <summary>
/// Gets the order fee associated with the specified order.
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in a <see cref="CashAmount"/> instance</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var security = parameters.Security;
var order = parameters.Order;
var fee = GetFee(order);
if(security.Symbol.ID.SecurityType == SecurityType.CryptoFuture)
{
var positionValue = security.Holdings.GetQuantityValue(order.AbsoluteQuantity, security.Price);
return new OrderFee(new CashAmount(positionValue.Amount * fee, positionValue.Cash.Symbol));
}
if (order.Direction == OrderDirection.Buy)
{
// fees taken in the received currency
CurrencyPairUtil.DecomposeCurrencyPair(order.Symbol, out var baseCurrency, out _);
return new OrderFee(new CashAmount(order.AbsoluteQuantity * fee, baseCurrency));
}
// get order value in quote currency
var unitPrice = security.BidPrice;
if (order.Type == OrderType.Limit)
{
// limit order posted to the order book
unitPrice = ((LimitOrder)order).LimitPrice;
}
unitPrice *= security.SymbolProperties.ContractMultiplier;
return new OrderFee(new CashAmount(
unitPrice * order.AbsoluteQuantity * fee,
security.QuoteCurrency.Symbol));
}
/// <summary>
/// Gets the fee factor for the given order
/// </summary>
/// <param name="order">The order to get the fee factor for</param>
/// <returns>The fee factor for the given order</returns>
protected virtual decimal GetFee(Order order)
{
return GetFee(order, _makerFee, _takerFee);
}
private static decimal GetFee(Order order, decimal makerFee, decimal takerFee)
{
// apply fee factor, currently we do not model 30-day volume, so we use the first tier
var fee = takerFee;
var props = order.Properties as BybitOrderProperties;
if (order.Type == OrderType.Limit && ((props != null && props.PostOnly) || !order.IsMarketable))
{
// limit order posted to the order book
fee = makerFee;
}
return fee;
}
}
@@ -0,0 +1,44 @@
/*
* 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.Orders.Fees;
/// <summary>
/// Bybit futures fee model implementation
/// </summary>
public class BybitFuturesFeeModel : BybitFeeModel
{
/// <summary>
/// Tier 1 maker fees
/// https://learn.bybit.com/bybit-guide/bybit-trading-fees/
/// </summary>
public new const decimal MakerNonVIPFee = 0.0002m;
/// <summary>
/// Tier 1 taker fees
/// https://learn.bybit.com/bybit-guide/bybit-trading-fees/
/// </summary>
public new const decimal TakerNonVIPFee = 0.00055m;
/// <summary>
/// Initializes a new instance of the <see cref="BybitFuturesFeeModel"/> class
/// </summary>
/// <param name="makerFee">The accounts maker fee</param>
/// <param name="takerFee">The accounts taker fee</param>
public BybitFuturesFeeModel(decimal makerFee = MakerNonVIPFee, decimal takerFee = TakerNonVIPFee)
: base(makerFee, takerFee)
{
}
}
@@ -0,0 +1,64 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Represents a fee model specific to Charles Schwab.
/// </summary>
/// <see href="https://www.schwab.com/pricing"/>
public class CharlesSchwabFeeModel : FeeModel
{
/// <summary>
/// The exchange processing fee for standard option securities.
/// </summary>
private const decimal _optionIndexFee = 1m;
/// <summary>
/// Represents the fee associated with equity options transactions (per contract).
/// </summary>
private const decimal _optionFee = 0.65m;
/// <summary>
/// Calculates the order fee based on the security type and order parameters.
/// </summary>
/// <param name="parameters">The parameters for the order fee calculation, which include security and order details.</param>
/// <returns>
/// An <see cref="OrderFee"/> instance representing the calculated order fee.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Thrown when <paramref name="parameters"/> is <c>null</c>.
/// </exception>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
if (parameters.Security.Type.IsOption())
{
var feeRate = parameters.Security.Type switch
{
SecurityType.IndexOption => _optionIndexFee,
SecurityType.Option => _optionFee,
_ => 0m
};
return new OrderFee(new CashAmount(parameters.Order.AbsoluteQuantity * feeRate, Currencies.USD));
}
return OrderFee.Zero;
}
}
}
+137
View File
@@ -0,0 +1,137 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014-2023 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Represents a fee model specific to Coinbase.
/// This class extends the base fee model.
/// </summary>
public class CoinbaseFeeModel : FeeModel
{
/// <summary>
/// Level Advanced 1 maker fee
/// Tab "Fee tiers" on <see href="https://www.coinbase.com/advanced-fees"/>
/// </summary>
public const decimal MakerAdvanced1 = 0.006m;
/// <summary>
/// Level Advanced 1 taker fee
/// Tab "Fee tiers" on <see href="https://www.coinbase.com/advanced-fees"/>
/// </summary>
public const decimal TakerAdvanced1 = 0.008m;
/// <summary>
/// Stable Pairs maker fee
/// Tab "Stable pairs" on <see href="https://www.coinbase.com/advanced-fees"/>
/// </summary>
public const decimal MakerStablePairs = 0m;
/// <summary>
/// Stable Pairs taker fee
/// Tab "Stable pairs" on <see href="https://www.coinbase.com/advanced-fees"/>
/// </summary>
public const decimal TakerStableParis = 0.00001m;
private readonly decimal _makerFee;
private readonly decimal _takerFee;
/// <summary>
/// Create Coinbase Fee model setting fee values
/// </summary>
/// <param name="makerFee">Maker fee value</param>
/// <param name="takerFee">Taker fee value</param>
/// <remarks>By default: use Level Advanced 1 fees</remarks>
public CoinbaseFeeModel(decimal makerFee = MakerAdvanced1, decimal takerFee = TakerAdvanced1)
{
_makerFee = makerFee;
_takerFee = takerFee;
}
/// <summary>
/// Get the fee for this order in quote currency
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in quote currency</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
if (parameters == null)
{
throw new ArgumentNullException(nameof(parameters), "The 'parameters' argument cannot be null.");
}
var order = parameters.Order;
var security = parameters.Security;
var props = order.Properties as CoinbaseOrderProperties;
// marketable limit orders are considered takers
var isMaker = order.Type == OrderType.Limit && ((props != null && props.PostOnly) || !order.IsMarketable);
// Check if the current symbol is a StableCoin
var isStableCoin = Currencies.StablePairsCoinbase.Contains(security.Symbol.Value);
var feePercentage = GetFeePercentage(order.Time, isMaker, isStableCoin, _makerFee, _takerFee);
// get order value in quote currency, then apply maker/taker fee factor
var unitPrice = order.Direction == OrderDirection.Buy ? security.AskPrice : security.BidPrice;
unitPrice *= security.SymbolProperties.ContractMultiplier;
// currently we do not model 30-day volume, so we use the first tier
var fee = unitPrice * order.AbsoluteQuantity * feePercentage;
return new OrderFee(new CashAmount(fee, security.QuoteCurrency.Symbol));
}
/// <summary>
/// Returns the maker/taker fee percentage effective at the requested date.
/// </summary>
/// <param name="utcTime">The date/time requested (UTC)</param>
/// <param name="isMaker">true if the maker percentage fee is requested, false otherwise</param>
/// <param name="isStableCoin">true if the order security symbol is a StableCoin, false otherwise</param>
/// <param name="makerFee">maker fee amount</param>
/// <param name="takerFee">taker fee amount</param>
/// <returns>The fee percentage</returns>
protected static decimal GetFeePercentage(DateTime utcTime, bool isMaker, bool isStableCoin, decimal makerFee, decimal takerFee)
{
if (isStableCoin && utcTime < new DateTime(2022, 6, 1))
{
return isMaker ? 0m : 0.001m;
}
else if(isStableCoin)
{
return isMaker ? MakerStablePairs : TakerStableParis;
}
else if (utcTime < new DateTime(2019, 3, 23, 1, 30, 0))
{
return isMaker ? 0m : 0.003m;
}
else if (utcTime < new DateTime(2019, 10, 8, 0, 30, 0))
{
return isMaker ? 0.0015m : 0.0025m;
}
// https://www.coinbase.com/advanced-fees
// Level | Trading amount | Spot fees (Maker | Taker)
// Advanced 1 | >= $0 | 0.60% | 0.80%
return isMaker ? makerFee : takerFee;
}
}
}
+51
View File
@@ -0,0 +1,51 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an order fee model that always returns the same order fee.
/// </summary>
public class ConstantFeeModel : FeeModel
{
private readonly decimal _fee;
private readonly string _currency;
/// <summary>
/// Initializes a new instance of the <see cref="ConstantFeeModel"/> class with the specified <paramref name="fee"/>
/// </summary>
/// <param name="fee">The constant order fee used by the model</param>
/// <param name="currency">The currency of the order fee</param>
public ConstantFeeModel(decimal fee, string currency = "USD")
{
_fee = Math.Abs(fee);
_currency = currency;
}
/// <summary>
/// Returns the constant fee for the model in units of the account currency
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in units of the account currency</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
return new OrderFee(new CashAmount(_fee, _currency));
}
}
}
+130
View File
@@ -0,0 +1,130 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models Exante order fees.
/// According to:
/// <list type="bullet">
/// <item>https://support.exante.eu/hc/en-us/articles/115005873143-Fees-overview-exchange-imposed-fees?source=search</item>
/// <item>https://exante.eu/markets/</item>
/// </list>
/// </summary>
public class ExanteFeeModel : FeeModel
{
/// <summary>
/// Market USA rate
/// </summary>
public const decimal MarketUsaRate = 0.02m;
/// <summary>
/// Default rate
/// </summary>
public const decimal DefaultRate = 0.02m;
private readonly decimal _forexCommissionRate;
/// <summary>
/// Creates a new instance
/// </summary>
/// <param name="forexCommissionRate">Commission rate for FX operations</param>
public ExanteFeeModel(decimal forexCommissionRate = 0.25m)
{
_forexCommissionRate = forexCommissionRate;
}
/// <summary>
/// Gets the order fee associated with the specified order.
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in a <see cref="CashAmount"/> instance</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var order = parameters.Order;
var security = parameters.Security;
decimal feeResult;
string feeCurrency;
switch (security.Type)
{
case SecurityType.Forex:
var totalOrderValue = order.GetValue(security);
feeResult = Math.Abs(_forexCommissionRate * totalOrderValue);
feeCurrency = Currencies.USD;
break;
case SecurityType.Equity:
var equityFee = ComputeEquityFee(order);
feeResult = equityFee.Amount;
feeCurrency = equityFee.Currency;
break;
case SecurityType.Option:
case SecurityType.IndexOption:
var optionsFee = ComputeOptionFee(order);
feeResult = optionsFee.Amount;
feeCurrency = optionsFee.Currency;
break;
case SecurityType.Future:
case SecurityType.FutureOption:
feeResult = 1.5m;
feeCurrency = Currencies.USD;
break;
default:
throw new ArgumentException(Messages.FeeModel.UnsupportedSecurityType(security));
}
return new OrderFee(new CashAmount(feeResult, feeCurrency));
}
/// <summary>
/// Computes fee for equity order
/// </summary>
/// <param name="order">LEAN order</param>
private static CashAmount ComputeEquityFee(Order order)
{
switch (order.Symbol.ID.Market)
{
case Market.USA:
return new CashAmount(order.AbsoluteQuantity * MarketUsaRate, Currencies.USD);
default:
return new CashAmount(order.AbsoluteQuantity * order.Price * DefaultRate, Currencies.USD);
}
}
/// <summary>
/// Computes fee for option order
/// </summary>
/// <param name="order">LEAN order</param>
private static CashAmount ComputeOptionFee(Order order)
{
return order.Symbol.ID.Market switch
{
Market.USA => new CashAmount(order.AbsoluteQuantity * 1.5m, Currencies.USD),
_ =>
// ToDo: clarify the value for different exchanges
throw new ArgumentException(Messages.ExanteFeeModel.UnsupportedExchange(order))
};
}
}
}
+24
View File
@@ -0,0 +1,24 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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.Orders.Fees
{
/// <summary>
/// Eze fee model implementation
/// </summary>
public class EzeFeeModel : FeeModel
{
}
}
+71
View File
@@ -0,0 +1,71 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models FTX order fees
/// https://help.ftx.com/hc/en-us/articles/360024479432-Fees
/// </summary>
public class FTXFeeModel : FeeModel
{
/// <summary>
/// Tier 1 maker fees
/// </summary>
public virtual decimal MakerFee => 0.0002m;
/// <summary>
/// Tier 1 taker fees
/// </summary>
public virtual decimal TakerFee => 0.0007m;
/// <summary>
/// Get the fee for this order in quote currency
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in quote currency</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var order = parameters.Order;
var security = parameters.Security;
var props = order.Properties as FTXOrderProperties;
//taker by default
var fee = TakerFee;
var unitPrice = order.Direction == OrderDirection.Buy ? security.AskPrice : security.BidPrice;
unitPrice *= security.SymbolProperties.ContractMultiplier;
var currency = security.QuoteCurrency.Symbol;
//maker if limit
if (order.Type == OrderType.Limit && (props?.PostOnly == true || !order.IsMarketable))
{
fee = MakerFee;
if (order.Direction == OrderDirection.Buy)
{
unitPrice = 1;
currency = ((IBaseCurrencySymbol)security).BaseCurrency.Symbol;
}
}
// apply fee factor, currently we do not model 30-day volume, so we use the first tier
return new OrderFee(new CashAmount(
unitPrice * order.AbsoluteQuantity * fee,
currency));
}
}
}
+34
View File
@@ -0,0 +1,34 @@
/*
* 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.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models FTX order fees
/// https://help.ftx.us/hc/en-us/articles/360043579273-Fees
/// </summary>
public class FTXUSFeeModel : FTXFeeModel
{
/// <summary>
/// Tier 1 maker fees
/// </summary>
public override decimal MakerFee => 0.001m;
/// <summary>
/// Tier 1 taker fees
/// </summary>
public override decimal TakerFee => 0.004m;
}
}
+40
View File
@@ -0,0 +1,40 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Base class for any order fee model
/// </summary>
/// <remarks>Please use <see cref="FeeModel"/> as the base class for
/// any implementations of <see cref="IFeeModel"/></remarks>
public class FeeModel : IFeeModel
{
/// <summary>
/// Gets the order fee associated with the specified order.
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in a <see cref="CashAmount"/> instance</returns>
public virtual OrderFee GetOrderFee(OrderFeeParameters parameters)
{
return new OrderFee(new CashAmount(
0,
"USD"));
}
}
}
+76
View File
@@ -0,0 +1,76 @@
/*
* 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 QuantConnect.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models FXCM order fees
/// </summary>
public class FxcmFeeModel : FeeModel
{
private readonly string _currency;
private readonly HashSet<Symbol> _groupCommissionSchedule1 = new HashSet<Symbol>
{
Symbol.Create("EURUSD", SecurityType.Forex, Market.FXCM),
Symbol.Create("GBPUSD", SecurityType.Forex, Market.FXCM),
Symbol.Create("USDJPY", SecurityType.Forex, Market.FXCM),
Symbol.Create("USDCHF", SecurityType.Forex, Market.FXCM),
Symbol.Create("AUDUSD", SecurityType.Forex, Market.FXCM),
Symbol.Create("EURJPY", SecurityType.Forex, Market.FXCM),
Symbol.Create("GBPJPY", SecurityType.Forex, Market.FXCM),
};
/// <summary>
/// Creates a new instance
/// </summary>
/// <param name="currency">The currency of the order fee, for FXCM this is the account currency</param>
public FxcmFeeModel(string currency = "USD")
{
_currency = currency;
}
/// <summary>
/// Get the fee for this order in units of the account currency
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in units of the account currency</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
// From http://www.fxcm.com/forex/forex-pricing/ (on Oct 6th, 2015)
// Forex: $0.04 per side per 1k lot for EURUSD, GBPUSD, USDJPY, USDCHF, AUDUSD, EURJPY, GBPJPY
// $0.06 per side per 1k lot for other instruments
// From https://www.fxcm.com/uk/markets/cfds/frequently-asked-questions/
// CFD: no commissions
decimal fee = 0;
if (parameters.Security.Type == SecurityType.Forex)
{
var commissionRate = _groupCommissionSchedule1.Contains(parameters.Security.Symbol)
? 0.04m : 0.06m;
fee = Math.Abs(commissionRate * parameters.Order.AbsoluteQuantity / 1000);
}
return new OrderFee(new CashAmount(fee,
_currency));
}
}
}
+26
View File
@@ -0,0 +1,26 @@
/*
* 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;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models GDAX order fees
/// </summary>
[Obsolete("GDAXFeeModel is deprecated. Use CoinbaseFeeModel instead.")]
public class GDAXFeeModel : CoinbaseFeeModel
{ }
}
+58
View File
@@ -0,0 +1,58 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Represents a model the simulates order fees
/// </summary>
/// <remarks>Please use <see cref="FeeModel"/> as the base class for
/// any implementations of <see cref="IFeeModel"/></remarks>
public interface IFeeModel
{
/// <summary>
/// Gets the order fee associated with the specified order.
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in a <see cref="CashAmount"/> instance</returns>
OrderFee GetOrderFee(OrderFeeParameters parameters);
}
/// <summary>
/// Provide extension method for <see cref="IFeeModel"/> to enable
/// backwards compatibility of invocations.
/// </summary>
public static class FeeModelExtensions
{
/// <summary>
/// Gets the order fee associated with the specified order. This returns the cost
/// of the transaction in the account currency
/// </summary>
/// <param name="model">The fee model</param>
/// <param name="security">The security matching the order</param>
/// <param name="order">The order to compute fees for</param>
/// <returns>The cost of the order in units of the account currency</returns>
public static decimal GetOrderFee(this IFeeModel model, Security security, Order order)
{
var parameters = new OrderFeeParameters(security, order);
var fee = model.GetOrderFee(parameters);
return fee.Value.Amount;
}
}
}
+123
View File
@@ -0,0 +1,123 @@
/*
* 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.Securities;
using System;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides the default implementation of <see cref="IFeeModel"/> Refer to https://www.samco.in/technology/brokerage_calculator
/// </summary>
public class IndiaFeeModel : IFeeModel
{
/// <summary>
/// Brokerage calculation Factor
/// </summary>
protected virtual decimal BrokerageMultiplier { get; set; }
/// <summary>
/// Maximum brokerage per order
/// </summary>
protected virtual decimal MaxBrokerage { get; set; }
/// <summary>
/// Securities Transaction Tax calculation Factor
/// </summary>
protected virtual decimal SecuritiesTransactionTaxTotalMultiplier { get; set; }
/// <summary>
/// Exchange Transaction Charge calculation Factor
/// </summary>
protected virtual decimal ExchangeTransactionChargeMultiplier { get; set; }
/// <summary>
/// State Tax calculation Factor
/// </summary>
protected virtual decimal StateTaxMultiplier { get; set; }
/// <summary>
/// Sebi Charges calculation Factor
/// </summary>
protected virtual decimal SebiChargesMultiplier { get; set; }
/// <summary>
/// Stamp Charges calculation Factor
/// </summary>
protected virtual decimal StampChargesMultiplier { get; set; }
/// <summary>
/// Checks if Stamp Charges is calculated from order valur or turnover
/// </summary>
protected virtual bool IsStampChargesFromOrderValue { get; set; }
/// <summary>
/// Gets the order fee associated with the specified order.
/// </summary>
/// <param name="parameters">
/// A <see cref="OrderFeeParameters"/> object containing the security and order
/// </param>
public OrderFee GetOrderFee(OrderFeeParameters parameters)
{
if (parameters.Security == null)
{
return OrderFee.Zero;
}
var orderValue = parameters.Order.GetValue(parameters.Security);
var fee = GetFee(orderValue);
return new OrderFee(new CashAmount(fee, Currencies.INR));
}
private decimal GetFee(decimal orderValue)
{
bool isSell = orderValue < 0;
orderValue = Math.Abs(orderValue);
var multiplied = orderValue * BrokerageMultiplier;
var brokerage = (multiplied > MaxBrokerage) ? MaxBrokerage : Math.Round(multiplied, 2);
var turnover = Math.Round(orderValue, 2);
decimal securitiesTransactionTaxTotal = 0;
if (isSell)
{
securitiesTransactionTaxTotal = Math.Round(orderValue * SecuritiesTransactionTaxTotalMultiplier, 2);
}
var exchangeTransactionCharge = Math.Round(turnover * ExchangeTransactionChargeMultiplier, 2);
var clearingCharge = 0;
var stateTax = Math.Round(StateTaxMultiplier * (brokerage + exchangeTransactionCharge), 2);
var sebiCharges = Math.Round((turnover * SebiChargesMultiplier), 2);
decimal stampCharges = 0;
if (!isSell)
{
if (IsStampChargesFromOrderValue)
{
stampCharges = Math.Round((orderValue * StampChargesMultiplier), 2);
}
else
{
stampCharges = Math.Round((turnover * StampChargesMultiplier), 2);
}
}
var totalTax = Math.Round(brokerage + securitiesTransactionTaxTotal + exchangeTransactionCharge + stampCharges + clearingCharge + stateTax + sebiCharges, 2);
return totalTax;
}
}
}
@@ -0,0 +1,502 @@
/*
* 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.Securities;
using QuantConnect.Orders.Fills;
using System.Collections.Generic;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides the default implementation of <see cref="IFeeModel"/>
/// </summary>
public class InteractiveBrokersFeeModel : FeeModel
{
private readonly decimal _forexCommissionRate;
private readonly decimal _forexMinimumOrderFee;
// option commission function takes number of contracts and the size of the option premium and returns total commission
private readonly Dictionary<string, Func<decimal, decimal, CashAmount>> _optionFee =
new Dictionary<string, Func<decimal, decimal, CashAmount>>();
#pragma warning disable CS1570
/// <summary>
/// Reference at https://www.interactivebrokers.com/en/index.php?f=commission&p=futures1
/// </summary>
#pragma warning restore CS1570
private readonly Dictionary<string, Func<Security, CashAmount>> _futureFee =
// IB fee + exchange fee
new()
{
{ Market.USA, UnitedStatesFutureFees },
{ Market.HKFE, HongKongFutureFees },
{ Market.EUREX, EUREXFutureFees }
};
/// <summary>
/// Initializes a new instance of the <see cref="ImmediateFillModel"/>
/// </summary>
/// <param name="monthlyForexTradeAmountInUSDollars">Monthly FX dollar volume traded</param>
/// <param name="monthlyOptionsTradeAmountInContracts">Monthly options contracts traded</param>
public InteractiveBrokersFeeModel(decimal monthlyForexTradeAmountInUSDollars = 0, decimal monthlyOptionsTradeAmountInContracts = 0)
{
ProcessForexRateSchedule(monthlyForexTradeAmountInUSDollars, out _forexCommissionRate, out _forexMinimumOrderFee);
Func<decimal, decimal, CashAmount> optionsCommissionFunc;
ProcessOptionsRateSchedule(monthlyOptionsTradeAmountInContracts, out optionsCommissionFunc);
// only USA for now
_optionFee.Add(Market.USA, optionsCommissionFunc);
}
/// <summary>
/// Gets the order fee associated with the specified order. This returns the cost
/// of the transaction in the account currency
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in units of the account currency</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var order = parameters.Order;
var security = parameters.Security;
// Option exercise for equity options is free of charge
if (order.Type == OrderType.OptionExercise)
{
var optionOrder = (OptionExerciseOrder)order;
// For Futures Options, contracts are charged the standard commission at expiration of the contract.
// Read more here: https://www1.interactivebrokers.com/en/index.php?f=14718#trading-related-fees
if (optionOrder.Symbol.ID.SecurityType == SecurityType.Option)
{
return OrderFee.Zero;
}
}
var quantity = order.AbsoluteQuantity;
decimal feeResult;
string feeCurrency;
var market = security.Symbol.ID.Market;
switch (security.Type)
{
case SecurityType.Forex:
// get the total order value in the account currency
var totalOrderValue = order.GetValue(security);
var fee = Math.Abs(_forexCommissionRate*totalOrderValue);
feeResult = Math.Max(_forexMinimumOrderFee, fee);
// IB Forex fees are all in USD
feeCurrency = Currencies.USD;
break;
case SecurityType.Option:
case SecurityType.IndexOption:
Func<decimal, decimal, CashAmount> optionsCommissionFunc;
if (!_optionFee.TryGetValue(market, out optionsCommissionFunc))
{
throw new KeyNotFoundException(Messages.InteractiveBrokersFeeModel.UnexpectedOptionMarket(market));
}
// applying commission function to the order
var optionFee = optionsCommissionFunc(quantity, GetPotentialOrderPrice(order, security));
feeResult = optionFee.Amount;
feeCurrency = optionFee.Currency;
break;
case SecurityType.Future:
case SecurityType.FutureOption:
// The futures options fee model is exactly the same as futures' fees on IB.
if (market == Market.Globex || market == Market.NYMEX
|| market == Market.CBOT || market == Market.ICE
|| market == Market.CFE || market == Market.COMEX
|| market == Market.CME || market == Market.NYSELIFFE)
{
// just in case...
market = Market.USA;
}
if (!_futureFee.TryGetValue(market, out var feeRatePerContractFunc))
{
throw new KeyNotFoundException(Messages.InteractiveBrokersFeeModel.UnexpectedFutureMarket(market));
}
var feeRatePerContract = feeRatePerContractFunc(security);
feeResult = quantity * feeRatePerContract.Amount;
feeCurrency = feeRatePerContract.Currency;
break;
case SecurityType.Equity:
EquityFee equityFee;
switch (market)
{
case Market.USA:
equityFee = new EquityFee(Currencies.USD, feePerShare: 0.005m, minimumFee: 1, maximumFeeRate: 0.005m);
break;
case Market.India:
equityFee = new EquityFee(Currencies.INR, feePerShare: 0.01m, minimumFee: 6, maximumFeeRate: 20);
break;
default:
throw new KeyNotFoundException(Messages.InteractiveBrokersFeeModel.UnexpectedEquityMarket(market));
}
var tradeValue = Math.Abs(order.GetValue(security));
//Per share fees
var tradeFee = equityFee.FeePerShare * quantity;
//Maximum Per Order: equityFee.MaximumFeeRate
//Minimum per order. $equityFee.MinimumFee
var maximumPerOrder = equityFee.MaximumFeeRate * tradeValue;
if (tradeFee < equityFee.MinimumFee)
{
tradeFee = equityFee.MinimumFee;
}
else if (tradeFee > maximumPerOrder)
{
tradeFee = maximumPerOrder;
}
feeCurrency = equityFee.Currency;
//Always return a positive fee.
feeResult = Math.Abs(tradeFee);
break;
case SecurityType.Cfd:
var value = Math.Abs(order.GetValue(security));
feeResult = 0.00002m * value; // 0.002%
feeCurrency = security.QuoteCurrency.Symbol;
var minimumFee = security.QuoteCurrency.Symbol switch
{
"JPY" => 40.0m,
"HKD" => 10.0m,
_ => 1.0m
};
feeResult = Math.Max(feeResult, minimumFee);
break;
default:
// unsupported security type
throw new ArgumentException(Messages.FeeModel.UnsupportedSecurityType(security));
}
return new OrderFee(new CashAmount(
feeResult,
feeCurrency));
}
/// <summary>
/// Approximates the order's price based on the order type
/// </summary>
protected static decimal GetPotentialOrderPrice(Order order, Security security)
{
decimal price = 0;
switch (order.Type)
{
case OrderType.TrailingStop:
price = (order as TrailingStopOrder).StopPrice;
break;
case OrderType.StopMarket:
price = (order as StopMarketOrder).StopPrice;
break;
case OrderType.ComboMarket:
case OrderType.MarketOnOpen:
case OrderType.MarketOnClose:
case OrderType.Market:
decimal securityPrice;
if (order.Direction == OrderDirection.Buy)
{
price = security.BidPrice;
}
else
{
price = security.AskPrice;
}
break;
case OrderType.ComboLimit:
price = (order as ComboLimitOrder).GroupOrderManager.LimitPrice;
break;
case OrderType.ComboLegLimit:
price = (order as ComboLegLimitOrder).LimitPrice;
break;
case OrderType.StopLimit:
price = (order as StopLimitOrder).LimitPrice;
break;
case OrderType.LimitIfTouched:
price = (order as LimitIfTouchedOrder).LimitPrice;
break;
case OrderType.Limit:
price = (order as LimitOrder).LimitPrice;
break;
}
return price;
}
/// <summary>
/// Determines which tier an account falls into based on the monthly trading volume
/// </summary>
private static void ProcessForexRateSchedule(decimal monthlyForexTradeAmountInUSDollars, out decimal commissionRate, out decimal minimumOrderFee)
{
const decimal bp = 0.0001m;
if (monthlyForexTradeAmountInUSDollars <= 1000000000) // 1 billion
{
commissionRate = 0.20m * bp;
minimumOrderFee = 2.00m;
}
else if (monthlyForexTradeAmountInUSDollars <= 2000000000) // 2 billion
{
commissionRate = 0.15m * bp;
minimumOrderFee = 1.50m;
}
else if (monthlyForexTradeAmountInUSDollars <= 5000000000) // 5 billion
{
commissionRate = 0.10m * bp;
minimumOrderFee = 1.25m;
}
else
{
commissionRate = 0.08m * bp;
minimumOrderFee = 1.00m;
}
}
/// <summary>
/// Determines which tier an account falls into based on the monthly trading volume
/// </summary>
private static void ProcessOptionsRateSchedule(decimal monthlyOptionsTradeAmountInContracts, out Func<decimal, decimal, CashAmount> optionsCommissionFunc)
{
if (monthlyOptionsTradeAmountInContracts <= 10000)
{
optionsCommissionFunc = (orderSize, premium) =>
{
var commissionRate = premium >= 0.1m ?
0.65m :
(0.05m <= premium && premium < 0.1m ? 0.5m : 0.25m);
return new CashAmount(Math.Max(orderSize * commissionRate, 1.0m), Currencies.USD);
};
}
else if (monthlyOptionsTradeAmountInContracts <= 50000)
{
optionsCommissionFunc = (orderSize, premium) =>
{
var commissionRate = premium >= 0.05m ? 0.5m : 0.25m;
return new CashAmount(Math.Max(orderSize * commissionRate, 1.0m), Currencies.USD);
};
}
else if (monthlyOptionsTradeAmountInContracts <= 100000)
{
optionsCommissionFunc = (orderSize, premium) =>
{
var commissionRate = 0.25m;
return new CashAmount(Math.Max(orderSize * commissionRate, 1.0m), Currencies.USD);
};
}
else
{
optionsCommissionFunc = (orderSize, premium) =>
{
var commissionRate = 0.15m;
return new CashAmount(Math.Max(orderSize * commissionRate, 1.0m), Currencies.USD);
};
}
}
private static CashAmount UnitedStatesFutureFees(Security security)
{
IDictionary<string, decimal> fees, exchangeFees;
decimal ibFeePerContract, exchangeFeePerContract;
string symbol;
switch (security.Symbol.SecurityType)
{
case SecurityType.Future:
fees = _usaFuturesFees;
exchangeFees = _usaFuturesExchangeFees;
symbol = security.Symbol.ID.Symbol;
break;
case SecurityType.FutureOption:
fees = _usaFutureOptionsFees;
exchangeFees = _usaFutureOptionsExchangeFees;
symbol = security.Symbol.Underlying.ID.Symbol;
break;
default:
throw new ArgumentException(Messages.InteractiveBrokersFeeModel.UnitedStatesFutureFeesUnsupportedSecurityType(security));
}
if (!fees.TryGetValue(symbol, out ibFeePerContract))
{
ibFeePerContract = 0.85m;
}
if (!exchangeFees.TryGetValue(symbol, out exchangeFeePerContract))
{
exchangeFeePerContract = 1.60m;
}
// Add exchange fees + IBKR regulatory fee (0.02)
return new CashAmount(ibFeePerContract + exchangeFeePerContract + 0.02m, Currencies.USD);
}
/// <summary>
/// See https://www.hkex.com.hk/Services/Rules-and-Forms-and-Fees/Fees/Listed-Derivatives/Trading/Transaction?sc_lang=en
/// </summary>
private static CashAmount HongKongFutureFees(Security security)
{
if (security.Symbol.ID.Symbol.Equals("HSI", StringComparison.InvariantCultureIgnoreCase))
{
// IB fee + exchange fee
return new CashAmount(30 + 10, Currencies.HKD);
}
decimal ibFeePerContract;
switch (security.QuoteCurrency.Symbol)
{
case Currencies.CNH:
ibFeePerContract = 13;
break;
case Currencies.HKD:
ibFeePerContract = 20;
break;
case Currencies.USD:
ibFeePerContract = 2.40m;
break;
default:
throw new ArgumentException(Messages.InteractiveBrokersFeeModel.HongKongFutureFeesUnexpectedQuoteCurrency(security));
}
// let's add a 50% extra charge for exchange fees
return new CashAmount(ibFeePerContract * 1.5m, security.QuoteCurrency.Symbol);
}
private static CashAmount EUREXFutureFees(Security security)
{
IDictionary<string, decimal> fees, exchangeFees;
decimal ibFeePerContract, exchangeFeePerContract;
string symbol;
switch (security.Symbol.SecurityType)
{
case SecurityType.Future:
fees = _eurexFuturesFees;
exchangeFees = _eurexFuturesExchangeFees;
symbol = security.Symbol.ID.Symbol;
break;
default:
throw new ArgumentException(Messages.InteractiveBrokersFeeModel.EUREXFutureFeesUnsupportedSecurityType(security));
}
if (!fees.TryGetValue(symbol, out ibFeePerContract))
{
ibFeePerContract = 1.00m;
}
if (!exchangeFees.TryGetValue(symbol, out exchangeFeePerContract))
{
exchangeFeePerContract = 0.00m;
}
// Add exchange fees + IBKR regulatory fee (0.02)
return new CashAmount(ibFeePerContract + exchangeFeePerContract + 0.02m, Currencies.EUR);
}
/// <summary>
/// Reference at https://www.interactivebrokers.com/en/pricing/commissions-futures.php?re=amer
/// </summary>
private static readonly Dictionary<string, decimal> _usaFuturesFees = new()
{
// Micro E-mini Futures
{ "MYM", 0.25m }, { "M2K", 0.25m }, { "MES", 0.25m }, { "MNQ", 0.25m }, { "2YY", 0.25m }, { "5YY", 0.25m }, { "10Y", 0.25m },
{ "30Y", 0.25m }, { "MCL", 0.25m }, { "MGC", 0.25m }, { "SIL", 0.25m },
// Cryptocurrency Futures
{ "BTC", 5m }, { "MBT", 2.25m }, { "ETH", 3m }, { "MET", 0.20m }, { "MIB", 2.25m }, { "MRB", 0.20m },
// E-mini FX (currencies) Futures
{ "E7", 0.50m }, { "J7", 0.50m },
// Micro E-mini FX (currencies) Futures
{ "M6E", 0.15m }, { "M6A", 0.15m }, { "M6B", 0.15m }, { "MCD", 0.15m }, { "MJY", 0.15m }, { "MSF", 0.15m }, { "M6J", 0.15m },
{ "MIR", 0.15m }, { "M6C", 0.15m }, { "M6S", 0.15m }, { "MNH", 0.15m },
};
/// <summary>
/// Reference at https://www.interactivebrokers.com/en/pricing/commissions-futures-europe.php?re=europe
/// </summary>
private static readonly Dictionary<string, decimal> _eurexFuturesFees = new()
{
// Futures
{ "FESX", 1.00m },
};
private static readonly Dictionary<string, decimal> _usaFutureOptionsFees = new()
{
// Micro E-mini Future Options
{ "MYM", 0.25m }, { "M2K", 0.25m }, { "MES", 0.25m }, { "MNQ", 0.25m }, { "2YY", 0.25m }, { "5YY", 0.25m }, { "10Y", 0.25m },
{ "30Y", 0.25m }, { "MCL", 0.25m }, { "MGC", 0.25m }, { "SIL", 0.25m },
// Cryptocurrency Future Options
{ "BTC", 5m }, { "MBT", 1.25m }, { "ETH", 3m }, { "MET", 0.10m }, { "MIB", 1.25m }, { "MRB", 0.10m }
};
private static readonly Dictionary<string, decimal> _usaFuturesExchangeFees = new()
{
// E-mini Futures
{ "ES", 1.28m }, { "NQ", 1.28m }, { "YM", 1.28m }, { "RTY", 1.28m }, { "EMD", 1.28m },
// Micro E-mini Futures
{ "MYM", 0.30m }, { "M2K", 0.30m }, { "MES", 0.30m }, { "MNQ", 0.30m }, { "2YY", 0.30m }, { "5YY", 0.30m }, { "10Y", 0.30m },
{ "30Y", 0.30m }, { "MCL", 0.30m }, { "MGC", 0.30m }, { "SIL", 0.30m },
// Cryptocurrency Futures
{ "BTC", 6m }, { "MBT", 2.5m }, { "ETH", 4m }, { "MET", 0.20m }, { "MIB", 2.5m }, { "MRB", 0.20m },
// E-mini FX (currencies) Futures
{ "E7", 0.85m }, { "J7", 0.85m },
// Micro E-mini FX (currencies) Futures
{ "M6E", 0.24m }, { "M6A", 0.24m }, { "M6B", 0.24m }, { "MCD", 0.24m }, { "MJY", 0.24m }, { "MSF", 0.24m }, { "M6J", 0.24m },
{ "MIR", 0.24m }, { "M6C", 0.24m }, { "M6S", 0.24m }, { "MNH", 0.24m },
};
private static readonly Dictionary<string, decimal> _eurexFuturesExchangeFees = new()
{
// Futures
{ "FESX", 0.00m },
};
private static readonly Dictionary<string, decimal> _usaFutureOptionsExchangeFees = new()
{
// E-mini Future Options
{ "ES", 0.55m }, { "NQ", 0.55m }, { "YM", 0.55m }, { "RTY", 0.55m }, { "EMD", 0.55m },
// Micro E-mini Future Options
{ "MYM", 0.20m }, { "M2K", 0.20m }, { "MES", 0.20m }, { "MNQ", 0.20m }, { "2YY", 0.20m }, { "5YY", 0.20m }, { "10Y", 0.20m },
{ "30Y", 0.20m }, { "MCL", 0.20m }, { "MGC", 0.20m }, { "SIL", 0.20m },
// Cryptocurrency Future Options
{ "BTC", 5m }, { "MBT", 2.5m }, { "ETH", 4m }, { "MET", 0.20m }, { "MIB", 2.5m }, { "MRB", 0.20m },
};
/// <summary>
/// Helper class to handle IB Equity fees
/// </summary>
private class EquityFee
{
public string Currency { get; }
public decimal FeePerShare { get; }
public decimal MinimumFee { get; }
public decimal MaximumFeeRate { get; }
public EquityFee(string currency,
decimal feePerShare,
decimal minimumFee,
decimal maximumFeeRate)
{
Currency = currency;
FeePerShare = feePerShare;
MinimumFee = minimumFee;
MaximumFeeRate = maximumFeeRate;
}
}
}
}
+113
View File
@@ -0,0 +1,113 @@
/*
* 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.Collections.Generic;
using System.Linq;
using QuantConnect.Securities;
using QuantConnect.Util;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models Kraken order fees
/// </summary>
public class KrakenFeeModel : FeeModel
{
/// <summary>
/// We don't use 30 day model, so using only tier1 fees.
/// https://www.kraken.com/features/fee-schedule#kraken-pro
/// </summary>
public const decimal MakerTier1CryptoFee = 0.0016m;
/// <summary>
/// We don't use 30 day model, so using only tier1 fees.
/// https://www.kraken.com/features/fee-schedule#kraken-pro
/// </summary>
public const decimal TakerTier1CryptoFee = 0.0026m;
/// <summary>
/// We don't use 30 day model, so using only tier1 fees.
/// https://www.kraken.com/features/fee-schedule#stablecoin-fx-pairs
/// </summary>
public const decimal Tier1FxFee = 0.002m;
/// <summary>
/// Fiats and stablecoins list that have own fee.
/// </summary>
public List<string> FxStablecoinList { get; init; } = new() {"CAD", "EUR", "GBP", "JPY", "USD", "USDT", "DAI", "USDC"};
/// <summary>
/// Get the fee for this order.
/// If sell - fees in base currency
/// If buy - fees in quote currency
/// It can be defined manually in <see cref="KrakenOrderProperties"/>
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The fee of the order</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var order = parameters.Order;
var security = parameters.Security;
var isBuy = order.Direction == OrderDirection.Buy;
var unitPrice = isBuy ? security.AskPrice : security.BidPrice;
if (order.Type == OrderType.Limit)
{
// limit order posted to the order book
unitPrice = ((LimitOrder)order).LimitPrice;
}
unitPrice *= security.SymbolProperties.ContractMultiplier;
var fee = TakerTier1CryptoFee;
var props = order.Properties as KrakenOrderProperties;
if (order.Type == OrderType.Limit &&
(props?.PostOnly == true || !order.IsMarketable))
{
// limit order posted to the order book
fee = MakerTier1CryptoFee;
}
if (isBuy && props?.FeeInBase == true)
{
isBuy = false;
}
if (!isBuy && props?.FeeInQuote == true)
{
isBuy = true;
}
if (FxStablecoinList.Any(i => security.Symbol.Value.StartsWith(i)))
{
fee = Tier1FxFee;
}
string actualBaseCurrency;
string actualQuoteCurrency;
CurrencyPairUtil.DecomposeCurrencyPair(security.Symbol, out actualBaseCurrency, out actualQuoteCurrency);
return new OrderFee(new CashAmount(
isBuy ? unitPrice * order.AbsoluteQuantity * fee : 1 * order.AbsoluteQuantity * fee,
isBuy ? actualQuoteCurrency : actualBaseCurrency));
}
}
}
@@ -0,0 +1,56 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// An order fee where the fee quantity has already been subtracted from the filled quantity so instead we subtracted
/// from the quote currency when applied to the portfolio
/// </summary>
/// <remarks>
/// This type of order fee is returned by some crypto brokerages (e.g. Bitfinex and Binance)
/// with buy orders with cash accounts.
/// </remarks>
public class ModifiedFillQuantityOrderFee : OrderFee
{
private readonly string _quoteCurrency;
private readonly decimal _contractMultiplier;
/// <summary>
/// Initializes a new instance of the <see cref="ModifiedFillQuantityOrderFee"/> class
/// </summary>
/// <param name="orderFee">The order fee</param>
/// <param name="quoteCurrency">The associated security quote currency</param>
/// <param name="contractMultiplier">The associated security contract multiplier</param>
public ModifiedFillQuantityOrderFee(CashAmount orderFee, string quoteCurrency, decimal contractMultiplier)
: base(orderFee)
{
_quoteCurrency = quoteCurrency;
_contractMultiplier = contractMultiplier;
}
/// <summary>
/// Applies the order fee to the given portfolio
/// </summary>
/// <param name="portfolio">The portfolio instance</param>
/// <param name="fill">The order fill event</param>
public override void ApplyToPortfolio(SecurityPortfolioManager portfolio, OrderEvent fill)
{
portfolio.CashBook[_quoteCurrency].AddAmount(-Value.Amount * fill.FillPrice * _contractMultiplier);
}
}
}
+76
View File
@@ -0,0 +1,76 @@
/*
* 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 ProtoBuf;
using QuantConnect.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Defines the result for <see cref="IFeeModel.GetOrderFee"/>
/// </summary>
[ProtoContract(SkipConstructor = true)]
public class OrderFee
{
/// <summary>
/// Gets the order fee
/// </summary>
[ProtoMember(1)]
public CashAmount Value { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="OrderFee"/> class
/// </summary>
/// <param name="orderFee">The order fee</param>
public OrderFee(CashAmount orderFee)
{
Value = new CashAmount(
orderFee.Amount.Normalize(),
orderFee.Currency);
}
/// <summary>
/// Applies the order fee to the given portfolio
/// </summary>
/// <param name="portfolio">The portfolio instance</param>
/// <param name="fill">The order fill event</param>
public virtual void ApplyToPortfolio(SecurityPortfolioManager portfolio, OrderEvent fill)
{
portfolio.CashBook[Value.Currency].AddAmount(-Value.Amount);
}
/// <summary>
/// This is for backward compatibility with old 'decimal' order fee
/// </summary>
public override string ToString()
{
return $"{Value.Amount} {Value.Currency}";
}
/// <summary>
/// This is for backward compatibility with old 'decimal' order fee
/// </summary>
public static implicit operator decimal(OrderFee m)
{
return m.Value.Amount;
}
/// <summary>
/// Gets an instance of <see cref="OrderFee"/> that represents zero.
/// </summary>
public static readonly OrderFee Zero =
new OrderFee(new CashAmount(0, Currencies.NullCurrency));
}
}
+44
View File
@@ -0,0 +1,44 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Defines the parameters for <see cref="IFeeModel.GetOrderFee"/>
/// </summary>
public class OrderFeeParameters
{
/// <summary>
/// Gets the security
/// </summary>
public Security Security { get; }
/// <summary>
/// Gets the order
/// </summary>
public Order Order { get; }
/// <summary>
/// Initializes a new instance of the <see cref="OrderFeeParameters"/> class
/// </summary>
/// <param name="security">The security</param>
/// <param name="order">The order</param>
public OrderFeeParameters(Security security, Order order)
{
Security = security;
Order = order;
}
}
}
+131
View File
@@ -0,0 +1,131 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Represents a fee model specific to Public.com.
/// </summary>
/// <see href="https://public.com/disclosures/fee-schedule"/>
/// <remarks>
/// Equity trades are free during regular market hours and $2.99 per trade during extended hours.
/// Options on stocks and ETFs are free; index options cost $0.50 per contract.
/// Crypto trades carry a fee that depends on the order amount in USD.
/// The model uses the regular member tier and does not detect OTC stocks.
/// </remarks>
public class PublicFeeModel : FeeModel
{
/// <summary>
/// Flat per-trade fee for US-listed equity trades placed during extended market hours.
/// </summary>
private const decimal _extendedHoursEquityFee = 2.99m;
/// <summary>
/// Per-contract fee for index options (regular member tier).
/// </summary>
private const decimal _indexOptionContractFee = 0.50m;
/// <summary>
/// Crypto fee charged on orders above the flat-tier range: 1.25% of the order amount.
/// </summary>
private const decimal _cryptoPercentFee = 0.0125m;
/// <summary>
/// Gets the order fee for a given security and order.
/// </summary>
/// <param name="parameters">The parameters including the security and order details.</param>
/// <returns>A <see cref="OrderFee"/> in USD for the order.</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var order = parameters.Order;
var security = parameters.Security;
decimal fee;
switch (security.Type)
{
case SecurityType.Equity:
fee = GetEquityFee(security, order);
break;
case SecurityType.IndexOption:
fee = order.AbsoluteQuantity * _indexOptionContractFee;
break;
case SecurityType.Crypto:
fee = GetCryptoFee(security, order);
break;
default:
// Options on stocks and ETFs are commission-free on Public.com.
return OrderFee.Zero;
}
return new OrderFee(new CashAmount(fee, Currencies.USD));
}
/// <summary>
/// Returns the equity fee: free during regular market hours, a flat fee during extended hours.
/// </summary>
/// <param name="security">The traded security.</param>
/// <param name="order">The order, whose time decides whether the trade is during regular hours.</param>
/// <returns>The equity fee in USD.</returns>
private static decimal GetEquityFee(Security security, Order order)
{
var localOrderTime = order.Time.ConvertFromUtc(security.Exchange.TimeZone);
var isRegularHours = security.Exchange.Hours.IsOpen(localOrderTime, extendedMarketHours: false);
return isRegularHours ? 0m : _extendedHoursEquityFee;
}
/// <summary>
/// Returns the crypto fee for the order, tiered by the order amount in USD.
/// </summary>
/// <param name="security">The traded security.</param>
/// <param name="order">The order being placed.</param>
/// <returns>The crypto fee in USD.</returns>
private static decimal GetCryptoFee(Security security, Order order)
{
var orderAmount = security.Price * security.SymbolProperties.ContractMultiplier * order.AbsoluteQuantity;
if (orderAmount <= 10m)
{
return 0.49m;
}
if (orderAmount <= 25m)
{
return 0.69m;
}
if (orderAmount <= 50m)
{
return 1.19m;
}
if (orderAmount <= 100m)
{
return 1.69m;
}
if (orderAmount <= 250m)
{
return 3.29m;
}
if (orderAmount <= 500m)
{
return 6.29m;
}
return orderAmount * _cryptoPercentFee;
}
}
}
+50
View File
@@ -0,0 +1,50 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models RBI order fees
/// </summary>
public class RBIFeeModel : FeeModel
{
private readonly decimal _feesPerShare;
/// <summary>
/// Creates a new instance
/// </summary>
/// <param name="feesPerShare">The fees per share to apply</param>
/// <remarks>Default value is $0.005 per share</remarks>
public RBIFeeModel(decimal? feesPerShare = null)
{
_feesPerShare = feesPerShare ?? 0.005m;
}
/// <summary>
/// Get the fee for this order in quote currency
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in quote currency</returns>
public OrderFee GetOrderFee(OrderFeeParameters parameters)
{
return new OrderFee(new CashAmount(_feesPerShare * parameters.Order.AbsoluteQuantity, Currencies.USD));
}
}
}
+58
View File
@@ -0,0 +1,58 @@
/*
* 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.Orders.Fees
{
/// <summary>
/// Provides the default implementation of <see cref="IFeeModel"/> Refer to https://www.samco.in/technology/brokerage_calculator
/// </summary>
public class SamcoFeeModel : IndiaFeeModel
{
/// <summary>
/// Brokerage calculation Factor
/// </summary>
protected override decimal BrokerageMultiplier => 0.0002M;
/// <summary>
/// Maximum brokerage per order
/// </summary>
protected override decimal MaxBrokerage => 20;
/// <summary>
/// Securities Transaction Tax calculation Factor
/// </summary>
protected override decimal SecuritiesTransactionTaxTotalMultiplier => 0.00025M;
/// <summary>
/// Exchange Transaction Charge calculation Factor
/// </summary>
protected override decimal ExchangeTransactionChargeMultiplier => 0.0000345M;
/// <summary>
/// State Tax calculation Factor
/// </summary>
protected override decimal StateTaxMultiplier => 0.18M;
/// <summary>
/// Sebi Charges calculation Factor
/// </summary>
protected override decimal SebiChargesMultiplier => 0.000001M;
/// <summary>
/// Stamp Charges calculation Factor
/// </summary>
protected override decimal StampChargesMultiplier => 0.00003M;
}
}
@@ -0,0 +1,48 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models TDAmeritrade order fees
/// </summary>
public class TDAmeritradeFeeModel : FeeModel
{
/// <summary>
/// Get the fee for this order in quote currency
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in quote currency</returns>
public OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var order = parameters.Order;
var symbolSecurityType = order.Symbol.SecurityType;
switch(symbolSecurityType)
{
case SecurityType.Equity:
return new OrderFee(new CashAmount(0m, Currencies.USD));
case SecurityType.Option:
return new OrderFee(new CashAmount(0.65m * order.AbsoluteQuantity, Currencies.USD));
};
throw new System.ArgumentException(Messages.TDAmeritradeFeeModel.UnsupportedSecurityType(symbolSecurityType));
}
}
}
+97
View File
@@ -0,0 +1,97 @@
/*
* 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.Brokerages;
using QuantConnect.Securities;
using System;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Represents a fee model specific to Tastytrade.
/// </summary>
/// <see href="https://tastytrade.com/pricing/"/>
public class TastytradeFeeModel : FeeModel
{
/// <summary>
/// Represents the fee associated with equity options transactions (per contract).
/// </summary>
private const decimal _optionFeeOpen = 1m;
/// <summary>
/// The fee associated with futures transactions (per contract).
/// </summary>
private const decimal _futureFee = 1.25m;
/// <summary>
/// The fee associated with futures options transactions (per contract).
/// </summary>
private const decimal _futureOptionFeeOpen = 2.5m;
/// <summary>
/// Gets the order fee for a given security and order.
/// </summary>
/// <param name="parameters">The parameters including the security and order details.</param>
/// <returns>
/// A <see cref="OrderFee"/> instance representing the total fee for the order,
/// or <see cref="OrderFee.Zero"/> if no fee is applicable.
/// </returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var feeRate = default(decimal);
switch (parameters.Security.Type)
{
case SecurityType.Option:
case SecurityType.IndexOption:
feeRate = IsOpenPosition(parameters.Order.Direction, parameters.Security.Holdings.Quantity) ? _optionFeeOpen : 0m;
break;
case SecurityType.Future:
feeRate = _futureFee;
break;
case SecurityType.FutureOption:
feeRate = IsOpenPosition(parameters.Order.Direction, parameters.Security.Holdings.Quantity) ? _futureOptionFeeOpen : 0m;
break;
default:
break;
}
return new OrderFee(new CashAmount(parameters.Order.AbsoluteQuantity * feeRate, Currencies.USD));
}
/// <summary>
/// Determines whether the specified order represents the opening of a new position.
/// </summary>
/// <param name="orderDirection">The direction of the order (buy/sell).</param>
/// <param name="holdingsQuantity">The current holdings quantity for the security.</param>
/// <returns>
/// <c>true</c> if the order is intended to open a new position; otherwise, <c>false</c>.
/// </returns>
/// <exception cref="NotSupportedException">
/// Thrown when the resolved <see cref="OrderPosition"/> is not recognized.
/// </exception>
private static bool IsOpenPosition(OrderDirection orderDirection, decimal holdingsQuantity)
{
var orderPosition = BrokerageExtensions.GetOrderPosition(orderDirection, holdingsQuantity);
return orderPosition switch
{
OrderPosition.BuyToClose or OrderPosition.SellToClose => false,
OrderPosition.BuyToOpen or OrderPosition.SellToOpen => true,
_ => throw new NotSupportedException($"{nameof(TastytradeFeeModel)}.{nameof(IsOpenPosition)}: Unsupported order position: {orderPosition}")
};
}
}
}
+102
View File
@@ -0,0 +1,102 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Represents a fee model specific to TradeStation.
/// </summary>
/// <see href="https://www.tradestation.com/pricing"/>
/// <remarks>
/// It is $0 for domestic and $5 for international clients for normal equities trades up to 10,000 shares, then $0.005 per share after.
/// Options are $0.60 per contract, per side, and an extra $1 for index options
/// </remarks>
public class TradeStationFeeModel : FeeModel
{
/// <summary>
/// Represents the fee associated with equity options transactions (per contract).
/// </summary>
private const decimal _equityOptionFee = 0.6m;
/// <summary>
/// Represents the fee associated with index options transactions (per contract).
/// </summary>
private const decimal _indexOptionFee = 1m;
/// <summary>
/// Represents the fee associated with futures transactions (per contract, per side).
/// </summary>
private const decimal _futuresFee = 1.5m;
/// <summary>
/// Gets the commission per trade based on the residency status of the entity or person.
/// </summary>
private decimal CommissionPerTrade => USResident ? 0m : 5.0m;
/// <summary>
/// Gets or sets a value indicating whether the entity or person is a resident of the United States.
/// </summary>
/// <value>
/// <c>true</c> if the entity or person is a US resident; otherwise, <c>false</c>.
/// </value>
public bool USResident { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="TradeStationFeeModel"/> class.
/// </summary>
/// <param name="usResident">
/// A boolean value indicating whether the entity or person is a US resident.
/// Default is <c>true</c>.
/// </param>
public TradeStationFeeModel(bool usResident = true)
{
USResident = usResident;
}
/// <summary>
/// Calculates the order fee based on the security type and order parameters.
/// </summary>
/// <param name="parameters">The parameters for the order fee calculation, which include security and order details.</param>
/// <returns>
/// An <see cref="OrderFee"/> instance representing the calculated order fee.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Thrown when <paramref name="parameters"/> is <c>null</c>.
/// </exception>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
if (parameters == null)
{
throw new ArgumentNullException(nameof(parameters), "Order fee parameters cannot be null.");
}
switch (parameters.Security.Type)
{
case SecurityType.Option:
return new OrderFee(new CashAmount(CommissionPerTrade + parameters.Order.AbsoluteQuantity * _equityOptionFee, Currencies.USD));
case SecurityType.IndexOption:
return new OrderFee(new CashAmount(CommissionPerTrade + parameters.Order.AbsoluteQuantity * _indexOptionFee, Currencies.USD));
case SecurityType.Future:
return new OrderFee(new CashAmount(parameters.Order.AbsoluteQuantity * _futuresFee, Currencies.USD));
default:
return new OrderFee(new CashAmount(CommissionPerTrade, Currencies.USD));
}
}
}
}
+226
View File
@@ -0,0 +1,226 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Represents a fee model specific to Webull.
/// </summary>
/// <see href="https://www.webull.com/pricing"/>
/// <remarks>
/// Equity and standard options trades are commission-free on Webull.
/// Index options carry a flat $0.50 Webull contract fee plus a variable exchange proprietary fee
/// that depends on the underlying index symbol and the option's market price.
/// </remarks>
public class WebullFeeModel : FeeModel
{
/// <summary>
/// Webull contract fee applied to every index option contract, regardless of underlying.
/// </summary>
private const decimal _webullIndexOptionContractFee = 0.50m;
/// <summary>
/// Exchange proprietary fee for SPX options priced below $1.00.
/// </summary>
private const decimal _spxExchangeFeeBelow1 = 0.57m;
/// <summary>
/// Exchange proprietary fee for SPX options priced at or above $1.00.
/// </summary>
private const decimal _spxExchangeFeeAbove1 = 0.66m;
/// <summary>
/// Exchange proprietary fee for SPXW options priced below $1.00.
/// </summary>
private const decimal _spxwExchangeFeeBelow1 = 0.50m;
/// <summary>
/// Exchange proprietary fee for SPXW options priced at or above $1.00.
/// </summary>
private const decimal _spxwExchangeFeeAbove1 = 0.59m;
/// <summary>
/// VIX/VIXW exchange fee tier 1: option price at or below $0.10.
/// </summary>
private const decimal _vixExchangeFeeTier1 = 0.10m;
/// <summary>
/// VIX/VIXW exchange fee tier 2: option price between $0.11 and $0.99.
/// </summary>
private const decimal _vixExchangeFeeTier2 = 0.25m;
/// <summary>
/// VIX/VIXW exchange fee tier 3: option price between $1.00 and $1.99.
/// </summary>
private const decimal _vixExchangeFeeTier3 = 0.40m;
/// <summary>
/// VIX/VIXW exchange fee tier 4: option price at or above $2.00.
/// </summary>
private const decimal _vixExchangeFeeTier4 = 0.45m;
/// <summary>
/// XSP exchange fee for orders with fewer than 10 contracts.
/// </summary>
private const decimal _xspExchangeFeeSmall = 0.00m;
/// <summary>
/// XSP exchange fee for orders with 10 or more contracts.
/// </summary>
private const decimal _xspExchangeFeeLarge = 0.07m;
/// <summary>
/// DJX flat exchange proprietary fee per contract.
/// </summary>
private const decimal _djxExchangeFee = 0.18m;
/// <summary>
/// NDX/NDXP exchange fee for single-leg orders with premium below $25.
/// </summary>
private const decimal _ndxSingleLegFeeBelow25 = 0.50m;
/// <summary>
/// NDX/NDXP exchange fee for single-leg orders with premium at or above $25.
/// </summary>
private const decimal _ndxSingleLegFeeAbove25 = 0.75m;
/// <summary>
/// NDX/NDXP exchange fee for multi-leg orders with premium below $25.
/// </summary>
private const decimal _ndxMultiLegFeeBelow25 = 0.65m;
/// <summary>
/// NDX/NDXP exchange fee for multi-leg orders with premium at or above $25.
/// </summary>
private const decimal _ndxMultiLegFeeAbove25 = 0.90m;
/// <summary>
/// Gets the order fee for a given security and order.
/// </summary>
/// <param name="parameters">The parameters including the security and order details.</param>
/// <returns>
/// <see cref="OrderFee.Zero"/> for equity and standard options;
/// a per-contract fee for index options.
/// </returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
switch (parameters.Security.Type)
{
case SecurityType.IndexOption:
return new OrderFee(new CashAmount(GetIndexOptionFee(parameters), Currencies.USD));
default:
// Equity and Option are commission-free on Webull.
return OrderFee.Zero;
}
}
/// <summary>
/// Calculates the total per-contract fee for an index option order.
/// The total fee = (exchange proprietary fee + Webull contract fee) × quantity.
/// </summary>
/// <param name="parameters">Order fee parameters containing the security and order.</param>
/// <returns>Total fee amount in USD.</returns>
private static decimal GetIndexOptionFee(OrderFeeParameters parameters)
{
var order = parameters.Order;
var security = parameters.Security;
var quantity = order.AbsoluteQuantity;
var price = security.Price;
var underlying = security.Symbol.Underlying?.Value?.ToUpperInvariant() ?? string.Empty;
var isMultiLeg = order.Type == OrderType.ComboMarket
|| order.Type == OrderType.ComboLimit
|| order.Type == OrderType.ComboLegLimit;
var exchangeFee = GetIndexOptionExchangeFee(underlying, price, quantity, isMultiLeg);
return quantity * (exchangeFee + _webullIndexOptionContractFee);
}
/// <summary>
/// Returns the exchange proprietary fee per contract for an index option, based on
/// the underlying ticker, the option's current price, order quantity, and leg type.
/// </summary>
/// <param name="underlying">Uppercase underlying ticker (e.g. "SPX", "VIX").</param>
/// <param name="price">Current market price of the option.</param>
/// <param name="quantity">Absolute number of contracts in the order.</param>
/// <param name="isMultiLeg">True when the order is a combo/multi-leg order.</param>
/// <returns>Exchange fee per contract in USD.</returns>
private static decimal GetIndexOptionExchangeFee(string underlying, decimal price, decimal quantity, bool isMultiLeg)
{
switch (underlying)
{
case "SPX":
return price < 1m ? _spxExchangeFeeBelow1 : _spxExchangeFeeAbove1;
case "SPXW":
return price < 1m ? _spxwExchangeFeeBelow1 : _spxwExchangeFeeAbove1;
case "VIX":
case "VIXW":
return GetVixExchangeFee(price);
case "XSP":
return quantity < 10m ? _xspExchangeFeeSmall : _xspExchangeFeeLarge;
case "DJX":
return _djxExchangeFee;
case "NDX":
case "NDXP":
return GetNdxExchangeFee(price, isMultiLeg);
default:
return 0m;
}
}
/// <summary>
/// Returns the VIX/VIXW exchange fee for a simple order based on the option price tier.
/// </summary>
private static decimal GetVixExchangeFee(decimal price)
{
if (price <= 0.10m)
{
return _vixExchangeFeeTier1;
}
if (price <= 0.99m)
{
return _vixExchangeFeeTier2;
}
if (price <= 1.99m)
{
return _vixExchangeFeeTier3;
}
return _vixExchangeFeeTier4;
}
/// <summary>
/// Returns the NDX/NDXP exchange fee per contract based on premium tier and order leg type.
/// </summary>
private static decimal GetNdxExchangeFee(decimal price, bool isMultiLeg)
{
if (isMultiLeg)
{
return price < 25m ? _ndxMultiLegFeeBelow25 : _ndxMultiLegFeeAbove25;
}
return price < 25m ? _ndxSingleLegFeeBelow25 : _ndxSingleLegFeeAbove25;
}
}
}
+50
View File
@@ -0,0 +1,50 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees
{
/// <summary>
/// Provides an implementation of <see cref="FeeModel"/> that models Wolverine order fees
/// </summary>
public class WolverineFeeModel : FeeModel
{
private readonly decimal _feesPerShare;
/// <summary>
/// Creates a new instance
/// </summary>
/// <param name="feesPerShare">The fees per share to apply</param>
/// <remarks>Default value is $0.005 per share</remarks>
public WolverineFeeModel(decimal? feesPerShare = null)
{
_feesPerShare = feesPerShare ?? 0.005m;
}
/// <summary>
/// Get the fee for this order in quote currency
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in quote currency</returns>
public OrderFee GetOrderFee(OrderFeeParameters parameters)
{
return new OrderFee(new CashAmount(_feesPerShare * parameters.Order.AbsoluteQuantity, Currencies.USD));
}
}
}
+63
View File
@@ -0,0 +1,63 @@
/*
* 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.Orders.Fees
{
/// <summary>
/// Provides the default implementation of <see cref="IFeeModel"/> Refer to https://www.samco.in/technology/brokerage_calculator
/// </summary>
public class ZerodhaFeeModel : IndiaFeeModel
{
/// <summary>
/// Brokerage calculation Factor
/// </summary>
protected override decimal BrokerageMultiplier => 0.0003M;
/// <summary>
/// Maximum brokerage per order
/// </summary>
protected override decimal MaxBrokerage => 20;
/// <summary>
/// Securities Transaction Tax calculation Factor
/// </summary>
protected override decimal SecuritiesTransactionTaxTotalMultiplier => 0.00025M;
/// <summary>
/// Exchange Transaction Charge calculation Factor
/// </summary>
protected override decimal ExchangeTransactionChargeMultiplier => 0.0000345M;
/// <summary>
/// State Tax calculation Factor
/// </summary>
protected override decimal StateTaxMultiplier => 0.18M;
/// <summary>
/// Sebi Charges calculation Factor
/// </summary>
protected override decimal SebiChargesMultiplier => 0.000001M;
/// <summary>
/// Stamp Charges calculation Factor
/// </summary>
protected override decimal StampChargesMultiplier => 0.00003M;
/// <summary>
/// Checks if Stamp Charges is calculated from order valur or turnover
/// </summary>
protected override bool IsStampChargesFromOrderValue => true;
}
}
+92
View File
@@ -0,0 +1,92 @@
/*
* 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.Securities;
namespace QuantConnect.Orders.Fees;
/// <summary>
/// dYdX fee model implementation
/// </summary>
public class dYdXFeeModel : FeeModel
{
/// <summary>
/// Tier 1 maker fees
/// https://dydx.trade/portfolio/fees
/// </summary>
private const decimal MakerTier1Fee = 0.0001m;
/// <summary>
/// Tier 1 taker fees
/// https://dydx.trade/portfolio/fees
/// </summary>
private const decimal TakerTier1Fee = 0.0005m;
private readonly decimal _makerFee;
private readonly decimal _takerFee;
/// <summary>
/// Creates Binance fee model setting fees values
/// </summary>
/// <param name="mFee">Maker fee value</param>
/// <param name="tFee">Taker fee value</param>
public dYdXFeeModel(decimal mFee = MakerTier1Fee, decimal tFee = TakerTier1Fee)
{
_makerFee = mFee;
_takerFee = tFee;
}
/// <summary>
/// Gets the order fee associated with the specified order.
/// </summary>
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
/// containing the security and order</param>
/// <returns>The cost of the order in a <see cref="CashAmount"/> instance</returns>
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
{
var security = parameters.Security;
var order = parameters.Order;
var fee = GetFee(order);
var positionValue = security.Holdings.GetQuantityValue(order.AbsoluteQuantity, security.Price);
return new OrderFee(new CashAmount(positionValue.Amount * fee, positionValue.Cash.Symbol));
}
/// <summary>
/// Gets the fee factor for the given order
/// </summary>
/// <param name="order">The order to get the fee factor for</param>
/// <returns>The fee factor for the given order</returns>
protected virtual decimal GetFee(Order order)
{
return GetFee(order, _makerFee, _takerFee);
}
private static decimal GetFee(Order order, decimal makerFee, decimal takerFee)
{
// apply fee factor, currently we do not model 30-day volume, so we use the first tier
var fee = takerFee;
var props = order.Properties as dYdXOrderProperties;
if (order.Type == OrderType.Limit && (props is { PostOnly: true } || !order.IsMarketable))
{
// limit order posted to the order book
fee = makerFee;
}
return fee;
}
}