11/*
22 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
33 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4- *
5- * Licensed under the Apache License, Version 2.0 (the "License");
4+ *
5+ * Licensed under the Apache License, Version 2.0 (the "License");
66 * you may not use this file except in compliance with the License.
77 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8- *
8+ *
99 * Unless required by applicable law or agreed to in writing, software
1010 * distributed under the License is distributed on an "AS IS" BASIS,
1111 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2020using QuantConnect . Interfaces ;
2121using QuantConnect . Logging ;
2222using QuantConnect . Orders ;
23+ using QuantConnect . Orders . Fees ;
2324using QuantConnect . Securities ;
2425using QuantConnect . Securities . Option ;
2526using QuantConnect . Util ;
@@ -28,8 +29,8 @@ namespace QuantConnect.Brokerages.Backtesting
2829{
2930 /// <summary>
3031 /// This market conditions simulator emulates exercising of short option positions in the portfolio.
31- /// Simulator implements basic no-arb argument: when time value of the option contract is close to zero
32- /// it assigns short legs getting profit close to expiration dates in deep ITM positions. User algorithm then receives
32+ /// Simulator implements basic no-arb argument: when time value of the option contract is close to zero
33+ /// it assigns short legs getting profit close to expiration dates in deep ITM positions. User algorithm then receives
3334 /// assignment event from LEAN. Simulator randomly scans for arbitrage opportunities every two hours or so.
3435 /// </summary>
3536 public class BasicOptionAssignmentSimulation : IBacktestingMarketSimulation
@@ -52,7 +53,7 @@ public class BasicOptionAssignmentSimulation : IBacktestingMarketSimulation
5253 private static Random _rand = new Random ( ( int ) 12345 ) ;
5354
5455 /// <summary>
55- /// We generate a list of time points when we would like to run our simulation. we then return true if the time is in the list.
56+ /// We generate a list of time points when we would like to run our simulation. we then return true if the time is in the list.
5657 /// </summary>
5758 /// <returns></returns>
5859 public bool IsReadyToSimulate ( IAlgorithm algorithm )
@@ -83,10 +84,10 @@ public bool IsReadyToSimulate(IAlgorithm algorithm)
8384 }
8485 }
8586 var randomizedScans = scans
86- . DistinctBy ( x => new DateTime ( x . Year , x . Month , x . Day , x . Hour , 0 , 0 ) ) // DistinctBy hour
87+ . DistinctBy ( x => new DateTime ( x . Year , x . Month , x . Day , x . Hour , 0 , 0 ) ) // DistinctBy hour
8788 . OrderBy ( x => x )
8889 . Select ( x => x . AddMinutes ( _rand . NextDouble ( ) * _assignmentScanPeriod . TotalMinutes ) ) ;
89-
90+
9091 _assignmentScans = new Queue < DateTime > ( randomizedScans ) ;
9192
9293 _lastUpdate = algorithm . UtcTime ;
@@ -98,7 +99,7 @@ public bool IsReadyToSimulate(IAlgorithm algorithm)
9899 // we fast forward through unused items
99100 if ( algorithm . UtcTime >= _assignmentScans . Peek ( ) )
100101 {
101- while ( _assignmentScans . Count > 0 &&
102+ while ( _assignmentScans . Count > 0 &&
102103 algorithm . UtcTime >= _assignmentScans . Peek ( ) )
103104 {
104105 _assignmentScans . Dequeue ( ) ;
@@ -115,7 +116,7 @@ public bool IsReadyToSimulate(IAlgorithm algorithm)
115116
116117 /// <summary>
117118 /// We simulate activity of market makers on expiration. Trying to get profit close to expiration dates in deep ITM positions.
118- /// This version of the simulator exercises short positions in full.
119+ /// This version of the simulator exercises short positions in full.
119120 /// </summary>
120121 public void SimulateMarketConditions ( IBrokerage brokerage , IAlgorithm algorithm )
121122 {
@@ -153,16 +154,16 @@ public void SimulateMarketConditions(IBrokerage brokerage, IAlgorithm algorithm)
153154
154155 private decimal EstimateArbitragePnL ( Option option , OptionHolding holding , Security underlying )
155156 {
156- // no-arb argument:
157- // if our long deep ITM position has a large B/A spread and almost no time value, it may be interesting for us
158- // to exercise the option and close the resulting position in underlying instrument, if we want to exit now.
157+ // no-arb argument:
158+ // if our long deep ITM position has a large B/A spread and almost no time value, it may be interesting for us
159+ // to exercise the option and close the resulting position in underlying instrument, if we want to exit now.
159160
160- // User's short option position is our long one.
161+ // User's short option position is our long one.
161162 // In order to sell ITM position we take option bid price as an input
162163 var optionPrice = option . BidPrice ;
163164
164- // we are interested in underlying bid price if we exercise calls and want to sell the underlying immediately.
165- // we are interested in underlying ask price if we exercise puts
165+ // we are interested in underlying bid price if we exercise calls and want to sell the underlying immediately.
166+ // we are interested in underlying ask price if we exercise puts
166167 var underlyingPrice = option . Symbol . ID . OptionRight == OptionRight . Call ?
167168 underlying . BidPrice :
168169 underlying . AskPrice ;
@@ -173,22 +174,28 @@ private decimal EstimateArbitragePnL(Option option, OptionHolding holding, Secur
173174
174175 // Scenario 1 (base): we just close option position
175176 var marketOrder1 = new MarketOrder ( option . Symbol , - holding . Quantity , option . LocalTime . ConvertToUtc ( option . Exchange . TimeZone ) ) ;
176- var orderFee1 = option . FeeModel . GetOrderFee ( option , marketOrder1 ) ;
177+ var orderFee1 = option . FeeModel . GetOrderFee (
178+ new OrderFeeParameters ( option , marketOrder1 ) ) ;
177179
178- var basePnL = ( optionPrice - holding . AveragePrice ) * - holding . Quantity * option . QuoteCurrency . ConversionRate * option . SymbolProperties . ContractMultiplier - orderFee1 ;
180+ var basePnL = ( optionPrice - holding . AveragePrice ) * - holding . Quantity
181+ * option . QuoteCurrency . ConversionRate
182+ * option . SymbolProperties . ContractMultiplier
183+ - orderFee1 . Value . Amount ;
179184
180185 // Scenario 2 (alternative): we exercise option and then close underlying position
181186 var optionExerciseOrder2 = new OptionExerciseOrder ( option . Symbol , ( int ) holding . AbsoluteQuantity , option . LocalTime . ConvertToUtc ( option . Exchange . TimeZone ) ) ;
182- var optionOrderFee2 = option . FeeModel . GetOrderFee ( option , optionExerciseOrder2 ) ;
187+ var optionOrderFee2 = option . FeeModel . GetOrderFee (
188+ new OrderFeeParameters ( option , optionExerciseOrder2 ) ) ;
183189
184190 var undelyingMarketOrder2 = new MarketOrder ( underlying . Symbol , - underlyingQuantity , underlying . LocalTime . ConvertToUtc ( underlying . Exchange . TimeZone ) ) ;
185- var undelyingOrderFee2 = underlying . FeeModel . GetOrderFee ( underlying , undelyingMarketOrder2 ) ;
191+ var undelyingOrderFee2 = underlying . FeeModel . GetOrderFee (
192+ new OrderFeeParameters ( underlying , undelyingMarketOrder2 ) ) ;
186193
187194 // calculating P/L of the two transactions (exercise option and then close underlying position)
188195 var altPnL = ( underlyingPrice - option . StrikePrice ) * underlyingQuantity * underlying . QuoteCurrency . ConversionRate * option . ContractUnitOfTrade
189- - undelyingOrderFee2
196+ - undelyingOrderFee2 . Value . Amount
190197 - holding . AveragePrice * holding . AbsoluteQuantity * option . SymbolProperties . ContractMultiplier * option . QuoteCurrency . ConversionRate
191- - optionOrderFee2 ;
198+ - optionOrderFee2 . Value . Amount ;
192199
193200 return altPnL - basePnL ;
194201 }
0 commit comments