/
CustomModelsAlgorithm.py
116 lines (97 loc) · 5.24 KB
/
CustomModelsAlgorithm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# 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.
from AlgorithmImports import *
import random
### <summary>
### Demonstration of using custom fee, slippage, fill, and buying power models for modelling transactions in backtesting.
### QuantConnect allows you to model all orders as deeply and accurately as you need.
### </summary>
### <meta name="tag" content="trading and orders" />
### <meta name="tag" content="transaction fees and slippage" />
### <meta name="tag" content="custom buying power models" />
### <meta name="tag" content="custom transaction models" />
### <meta name="tag" content="custom slippage models" />
### <meta name="tag" content="custom fee models" />
class CustomModelsAlgorithm(QCAlgorithm):
'''Demonstration of using custom fee, slippage, fill, and buying power models for modelling transactions in backtesting.
QuantConnect allows you to model all orders as deeply and accurately as you need.'''
def Initialize(self):
self.SetStartDate(2013,10,1) # Set Start Date
self.SetEndDate(2013,10,31) # Set End Date
self.security = self.AddEquity("SPY", Resolution.Hour)
self.spy = self.security.Symbol
# set our models
self.security.SetFeeModel(CustomFeeModel(self))
self.security.SetFillModel(CustomFillModel(self))
self.security.SetSlippageModel(CustomSlippageModel(self))
self.security.SetBuyingPowerModel(CustomBuyingPowerModel(self))
def OnData(self, data):
open_orders = self.Transactions.GetOpenOrders(self.spy)
if len(open_orders) != 0: return
if self.Time.day > 10 and self.security.Holdings.Quantity <= 0:
quantity = self.CalculateOrderQuantity(self.spy, .5)
self.Log(f"MarketOrder: {quantity}")
self.MarketOrder(self.spy, quantity, True) # async needed for partial fill market orders
elif self.Time.day > 20 and self.security.Holdings.Quantity >= 0:
quantity = self.CalculateOrderQuantity(self.spy, -.5)
self.Log(f"MarketOrder: {quantity}")
self.MarketOrder(self.spy, quantity, True) # async needed for partial fill market orders
# If we want to use methods from other models, you need to inherit from one of them
class CustomFillModel(ImmediateFillModel):
def __init__(self, algorithm):
self.algorithm = algorithm
self.absoluteRemainingByOrderId = {}
self.random = Random(387510346)
def MarketFill(self, asset, order):
absoluteRemaining = order.AbsoluteQuantity
if order.Id in self.absoluteRemainingByOrderId.keys():
absoluteRemaining = self.absoluteRemainingByOrderId[order.Id]
fill = super().MarketFill(asset, order)
absoluteFillQuantity = int(min(absoluteRemaining, self.random.Next(0, 2*int(order.AbsoluteQuantity))))
fill.FillQuantity = np.sign(order.Quantity) * absoluteFillQuantity
if absoluteRemaining == absoluteFillQuantity:
fill.Status = OrderStatus.Filled
if self.absoluteRemainingByOrderId.get(order.Id):
self.absoluteRemainingByOrderId.pop(order.Id)
else:
absoluteRemaining = absoluteRemaining - absoluteFillQuantity
self.absoluteRemainingByOrderId[order.Id] = absoluteRemaining
fill.Status = OrderStatus.PartiallyFilled
self.algorithm.Log(f"CustomFillModel: {fill}")
return fill
class CustomFeeModel(FeeModel):
def __init__(self, algorithm):
self.algorithm = algorithm
def GetOrderFee(self, parameters):
# custom fee math
fee = max(1, parameters.Security.Price
* parameters.Order.AbsoluteQuantity
* 0.00001)
self.algorithm.Log(f"CustomFeeModel: {fee}")
return OrderFee(CashAmount(fee, "USD"))
class CustomSlippageModel:
def __init__(self, algorithm):
self.algorithm = algorithm
def GetSlippageApproximation(self, asset, order):
# custom slippage math
slippage = asset.Price * 0.0001 * np.log10(2*float(order.AbsoluteQuantity))
self.algorithm.Log(f"CustomSlippageModel: {slippage}")
return slippage
class CustomBuyingPowerModel(BuyingPowerModel):
def __init__(self, algorithm):
self.algorithm = algorithm
def HasSufficientBuyingPowerForOrder(self, parameters):
# custom behavior: this model will assume that there is always enough buying power
hasSufficientBuyingPowerForOrderResult = HasSufficientBuyingPowerForOrderResult(True)
self.algorithm.Log(f"CustomBuyingPowerModel: {hasSufficientBuyingPowerForOrderResult.IsSufficient}")
return hasSufficientBuyingPowerForOrderResult