/// <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); if (fee.Value.Currency != security.QuoteCurrency.AccountCurrency) { throw new InvalidOperationException("The GetOrderFee extension method is only valid" + " for fee models returning fees in the account currency"); } return(fee.Value.Amount); }
/// <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))); }
/// <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(Invariant($"Unsupported security type: {security.Type}")); } return(new OrderFee(new CashAmount(feeResult, feeCurrency))); }
/// <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, parameters.Security.QuoteCurrency.AccountCurrency))); }
/// <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; // marketable limit orders are considered takers var isMaker = order.Type == OrderType.Limit && !order.IsMarketable; var feePercentage = GetFeePercentage(order.Time, isMaker); // 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> /// 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))); }
/// <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; // marketable limit orders are considered takers decimal fee = 0; // check limit order posted to the order book, 0% maker fee if (!(order.Type == OrderType.Limit && !order.IsMarketable)) { // get order value in quote currency, then apply 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 fee = unitPrice * order.AbsoluteQuantity * TakerFee; } return(new OrderFee(new CashAmount( fee, security.QuoteCurrency.Symbol))); }
/// <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; if (optionOrder.Symbol.ID.SecurityType == SecurityType.Option && optionOrder.Symbol.ID.Underlying.SecurityType == SecurityType.Equity) { return(new OrderFee(new CashAmount( 0, security.QuoteCurrency.AccountCurrency))); } } decimal feeResult = 0; 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); break; case SecurityType.Option: // applying commission function to the order feeResult = _optionsCommissionFunc(order.AbsoluteQuantity, order.Price); break; case SecurityType.Future: // currently we treat all futures as USD denominated generic US futures feeResult = order.AbsoluteQuantity * (0.85m + 1.0m); break; case SecurityType.Equity: var tradeValue = Math.Abs(order.GetValue(security)); //Per share fees var tradeFee = 0.005m * order.AbsoluteQuantity; //Maximum Per Order: 0.5% //Minimum per order. $1.0 var maximumPerOrder = 0.005m * tradeValue; if (tradeFee < 1) { tradeFee = 1; } else if (tradeFee > maximumPerOrder) { tradeFee = maximumPerOrder; } //Always return a positive fee. feeResult = Math.Abs(tradeFee); break; } // all other types default to zero fees return(new OrderFee(new CashAmount( feeResult, security.QuoteCurrency.AccountCurrency))); }
/// <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; if (optionOrder.Symbol.ID.SecurityType == SecurityType.Option && optionOrder.Symbol.ID.Underlying.SecurityType == SecurityType.Equity) { return(OrderFee.Zero); } } 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: Func <decimal, decimal, CashAmount> optionsCommissionFunc; if (!_optionFee.TryGetValue(market, out optionsCommissionFunc)) { throw new KeyNotFoundException($"InteractiveBrokersFeeModel(): unexpected option Market {market}"); } // applying commission function to the order var optionFee = optionsCommissionFunc(order.AbsoluteQuantity, order.Price); feeResult = optionFee.Amount; feeCurrency = optionFee.Currency; break; case SecurityType.Future: if (market == Market.Globex || market == Market.NYMEX || market == Market.CBOT || market == Market.ICE || market == Market.CBOE || market == Market.NSE) { // just in case... market = Market.USA; } CashAmount feeRatePerContract; if (!_futureFee.TryGetValue(market, out feeRatePerContract)) { throw new KeyNotFoundException($"InteractiveBrokersFeeModel(): unexpected future Market {market}"); } feeResult = order.AbsoluteQuantity * feeRatePerContract.Amount; feeCurrency = feeRatePerContract.Currency; break; case SecurityType.Equity: EquityFee equityFee; if (!_equityFee.TryGetValue(market, out equityFee)) { throw new KeyNotFoundException($"InteractiveBrokersFeeModel(): unexpected equity Market {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; } feeCurrency = equityFee.Currency; //Always return a positive fee. feeResult = Math.Abs(tradeFee); break; default: // unsupported security type throw new ArgumentException($"Unsupported security type: {security.Type}"); } return(new OrderFee(new CashAmount( feeResult, feeCurrency))); }
/// <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); } } 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: Func <decimal, decimal, CashAmount> optionsCommissionFunc; if (!_optionFee.TryGetValue(market, out optionsCommissionFunc)) { throw new KeyNotFoundException($"InteractiveBrokersFeeModel(): unexpected option Market {market}"); } // applying commission function to the order var optionFee = optionsCommissionFunc(order.AbsoluteQuantity, order.Price); 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.CBOE || market == Market.COMEX || market == Market.CME) { // just in case... market = Market.USA; } CashAmount feeRatePerContract; if (!_futureFee.TryGetValue(market, out feeRatePerContract)) { throw new KeyNotFoundException($"InteractiveBrokersFeeModel(): unexpected future Market {market}"); } feeResult = order.AbsoluteQuantity * feeRatePerContract.Amount; feeCurrency = feeRatePerContract.Currency; break; case SecurityType.Equity: EquityFee equityFee; switch (market) { case Market.USA: equityFee = new EquityFee("USD", feePerShare: 0.005m, minimumFee: 1, maximumFeeRate: 0.005m); break; default: throw new KeyNotFoundException($"InteractiveBrokersFeeModel(): unexpected equity Market {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; } feeCurrency = equityFee.Currency; //Always return a positive fee. feeResult = Math.Abs(tradeFee); break; default: // unsupported security type throw new ArgumentException(Invariant($"Unsupported security type: {security.Type}")); } return(new OrderFee(new CashAmount( feeResult, feeCurrency))); }
/// <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($"AlphaStreamsFeeModel(): unexpected equity Market {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(Invariant($"Unsupported security type: {security.Type}")); } }
/// <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, parameters.AccountCurrency))); }
/// <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))); }
/// <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"))); }
/// <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); } if (security.Type == 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))); } decimal feeRate; if (!_feeRates.TryGetValue(security.Type, out feeRate)) { throw new ArgumentException( Invariant($"Unsupported security type: {security.Type}.") ); } var value = order.AbsoluteQuantity; switch (security.Type) { case SecurityType.Equity: value = order.GetValue(security); break; case SecurityType.Forex: value = Math.Abs(order.GetValue(security)); break; } return(new OrderFee(new CashAmount(feeRate * value, Currencies.USD))); }
/// <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, parameters.Security.QuoteCurrency.AccountCurrency))); }