Custom Position Sizing
By default, the OptionStack platform provides various position sizing methods to appropriately size your trades. Specifically, you can easily size your trades based on:
- quantity – size the position based on the number of contracts
- risk – size the position based on the target risk of the trade
- reward – size the position based on target reward of the trade
- cost – size the position based on the target cost of the trade
- credit received – size the position based on the target credit received from trade
- delta – size the position based on target delta of the trade
- margin – size the position based on target margin of the trade
- netUnderlyingQuantityUncovered – size the position based on number of underlying stock that is not covered by short options
- netRollQuantity – when rolling the position, increase or decrease the net quantity of the trade
- netRollCost – when rolling the position, increase or decrease the quantity based on the net cost of the roll
However, if you want to size your trades using more advanced / custom sizing methods, you can also define your own custom position sizing algorithm by writing your strategy in Scala using the Advanced Scala Editor.
Here are the steps on how to construct your own custom position sizing methods for your trading strategies: (Custom Position Sizing Example)
- Create a New Strategy using the Advanced Scala Editor.
- Define your Custom Position Sizing function
// create your custom position sizing function
def mySizingFunction (trade:LegCriteriaT):Double = {
}
- Examine the attributes of the trade, and compute / return the number of contracts to trade
/**
* Custom position sizing function that compares the position size using maxRisk vs maxReward, and selects the smaller of the two
**/
def mySizingFunction (trade:LegCriteriaT):Double = {
var maxRewardTarget = 50000
var maxRiskTarget = 100000
// compute the maxReward / maxRisk of current trade
var tradeMaxReward = trade.maxReward.totalValue.d
var tradeMaxRisk = Math.abs (trade.maxRisk.totalValue.d)
// compute the quantities based on maxRiskTarget and maxRewardTarget
// risk is negative, so use absolute value to make quantity positive
var quantityBasedOnRisk = Math.abs(maxRiskTarget / tradeMaxRisk);
var quantityBasedOnReward = Math.abs (maxRewardTarget / tradeMaxReward);
// select the smaller between maxReward quantity versus maxRisk quantity
var selectedQuantity= Math.min (quantityBasedOnReward, quantityBasedOnRisk);
return selectedQuantity;
}
- Set the custom position sizing method when creating your trade using the sizeBy.customSizingFunction method:
// set the custom position sizing function
strategy1.sell("sellverticals.PutVertical1", "Enter Trade").sizeBy.customSizingFunction(mySizingFunction)
- Here is an example of using a custom position sizing method to size a trade
/**
Example of using custom position sizing functions to size a trade based on maxReward versus maxRisk combination
**/
class CustomPositionSizing (config:BacktestConfig) extends StrategyRunnerT (config) {
var AMD = this.getInstrument("AMD")
var AMD_studies_DayOfTheWeek__ = AMD.studies.DayOfTheWeek()
var AMD_studies_CumulativePercentageChange__ = AMD.studies.CumulativePercentageChange()
/**
* Custom position sizing function that compares the position size using maxRisk vs. maxReward, and selects the smaller of the two
**/
def mySizingFunction (trade:LegCriteriaT):Double = {
var maxRewardTarget = 50000
var maxRiskTarget = 100000
// compute the maxReward / maxRisk of current trade
var tradeMaxReward = trade.maxReward.totalValue.d
var tradeMaxRisk = Math.abs (trade.maxRisk.totalValue.d)
// compute the quantities based on maxRiskTarget and maxRewardTarget
// risk is negative, so use absolute value to make quantity a positive number
var quantityBasedOnRisk = Math.abs(maxRiskTarget / tradeMaxRisk);
var quantityBasedOnReward = Math.abs (maxRewardTarget / tradeMaxReward);
// select the smaller between maxReward quantity versus maxRisk quantity
var selectedQuantity= Math.min (quantityBasedOnReward, quantityBasedOnRisk);
return selectedQuantity;
}
def handleData () = {
// Define rules WHEN to trade
if (((AMD_studies_DayOfTheWeek__).===(2)) || ((AMD_studies_DayOfTheWeek__).===(6))) {
var strategy1 = AMD.strategies.verticals.PutVertical
var strategyfilter1 = strategy1.selectBy(false)
strategyfilter1.daysToExpiration(20, 40)
strategy1.selectHigherStrikeOptionBy().atTheMoney()
strategyfilter1.stepDistanceBetweenStrikes(3, 5)
strategy1.rankBy.max.riskReward
strategy1.setMaxOpenPositions(1)
// set the custom position sizing function defined above
strategy1.sell("sellverticals.PutVertical1", "Enter Trade").sizeBy.customSizingFunction(mySizingFunction)
}
}
}