Adds CustomBuyingPowerModelAlgorithm (#4824)

* Adds CustomBuyingPowerModelAlgorithm

This algorithms is an example on how to implement a custom buying power model.

In this particular case, it shows how to override `HasSufficientBuyingPowerForOrder` in order to place orders without sufficient buying power according to the default model.

* Upgrades CustomModelsAlgorithm to Include CustomBuyingPowerModel

The custom buying power model overrides `HasSufficientBuyingPowerForOrderResult` but it doesn't change the trades and, consequently, the regression statistics.
This commit is contained in:
Alexandre Catarino
2020-10-22 01:27:30 +01:00
committed by GitHub
parent b2ed398687
commit 84264ca7ef
7 changed files with 254 additions and 14 deletions
+20 -8
View File
@@ -27,16 +27,17 @@ import numpy as np
import random
### <summary>
### Demonstration of using custom fee, slippage and fill models for modelling transactions in backtesting.
### 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 and fill models for modelling transactions in backtesting.
'''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):
@@ -49,6 +50,7 @@ class CustomModelsAlgorithm(QCAlgorithm):
self.security.SetFeeModel(CustomFeeModel(self))
self.security.SetFillModel(CustomFillModel(self))
self.security.SetSlippageModel(CustomSlippageModel(self))
self.security.SetBuyingPowerModel(CustomBuyingPowerModel(self))
def OnData(self, data):
@@ -57,12 +59,12 @@ class CustomModelsAlgorithm(QCAlgorithm):
if self.Time.day > 10 and self.security.Holdings.Quantity <= 0:
quantity = self.CalculateOrderQuantity(self.spy, .5)
self.Log("MarketOrder: " + str(quantity))
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("MarketOrder: " + str(quantity))
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
@@ -90,7 +92,7 @@ class CustomFillModel(ImmediateFillModel):
absoluteRemaining = absoluteRemaining - absoluteFillQuantity
self.absoluteRemainingByOrderId[order.Id] = absoluteRemaining
fill.Status = OrderStatus.PartiallyFilled
self.algorithm.Log("CustomFillModel: " + str(fill))
self.algorithm.Log(f"CustomFillModel: {fill}")
return fill
class CustomFeeModel(FeeModel):
@@ -102,7 +104,7 @@ class CustomFeeModel(FeeModel):
fee = max(1, parameters.Security.Price
* parameters.Order.AbsoluteQuantity
* 0.00001)
self.algorithm.Log("CustomFeeModel: " + str(fee))
self.algorithm.Log(f"CustomFeeModel: {fee}")
return OrderFee(CashAmount(fee, "USD"))
class CustomSlippageModel:
@@ -112,5 +114,15 @@ class CustomSlippageModel:
def GetSlippageApproximation(self, asset, order):
# custom slippage math
slippage = asset.Price * 0.0001 * np.log10(2*float(order.AbsoluteQuantity))
self.algorithm.Log("CustomSlippageModel: " + str(slippage))
return slippage
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