Coding Variable Position Size in Pine
Posted: Thu Aug 11, 2022 4:19 am
Hi Pine Scripters,
I've been working on a simple script derived from Matt's in his latest YouTube video. I'm new to Pine (and to programming), but I am part-way through a strategy that allows the user to set a percentage of their account balance to risk per trade, where the balance is understood to be (strategy.initial_capital + strategy.netprofit). Starting with $1000 and a risk of 1%, were the first trade to be stopped out, the second trade would risk 1% of the remaining balance ($990) and so on. I understand the formulae there are for calculating position size, but I can''t seem to make the code work.
Here's the important bit:
Line one gets the difference between my buy and stop prices. Line four calculates 1% of the account balance. Line five, calculates the position size by dividing the latter by the former. Have I made a mistake in the calculation?
I then set the entry function for longs with 'pos_size' as the quantity:
Note that I calculate the position cash value under 'pos_size_cash'. I've tried using both pos_size and 'pos_size_cash' in the entry function, above, but the script seems to default to either buying one contract with every trade, or else buying miniscule amounts that I can't trace to what I've written. What's more, when I change the risk percentage user input (i_risk) in the strategy testing menu, the profit and loss figures - which should change - don't change at all.
I've tried troubleshooting by plotting each of the variables in the calculation above to the chart so I can check them. They all come out as you would expect, including the position size. I'm using an Ethereum chart on the 5 or 15m timeframes, so the position sizes are all fractions of 1, with corresponding cash values (Ethereum is worth about $1700 at the moment.)
So, for example, I have one order that shows readings for equity of $1000, equity risk-per-trade of $10, a price difference of $26, and a position size of 0.38 Eth, for a total of $657. Nevertheless, the script bought 0.0005 Eth, and for some reason the user-menu is set to risking $1 per trade.
I'll post the whole script below - just bear in mind that I'm not worried about the entry criteria and other bits and pieces, so much as understanding why the script doesn't buy the correct position size.
Thanks in advance for your time.
I've been working on a simple script derived from Matt's in his latest YouTube video. I'm new to Pine (and to programming), but I am part-way through a strategy that allows the user to set a percentage of their account balance to risk per trade, where the balance is understood to be (strategy.initial_capital + strategy.netprofit). Starting with $1000 and a risk of 1%, were the first trade to be stopped out, the second trade would risk 1% of the remaining balance ($990) and so on. I understand the formulae there are for calculating position size, but I can''t seem to make the code work.
Here's the important bit:
Code: Select all
long_diff = math.abs(long_entryprice - dc_lower_at_buy)
long_tp := long_entryprice + (ireward_multi * long_diff)
equitytorisk = equity * (i_risk/100)
pos_size = equitytorisk / long_diff
pos_size_cash = pos_size * long_entryprice
I then set the entry function for longs with 'pos_size' as the quantity:
Code: Select all
if long_condition
strategy.entry(id="Long", direction=strategy.long, qty=pos_size)
I've tried troubleshooting by plotting each of the variables in the calculation above to the chart so I can check them. They all come out as you would expect, including the position size. I'm using an Ethereum chart on the 5 or 15m timeframes, so the position sizes are all fractions of 1, with corresponding cash values (Ethereum is worth about $1700 at the moment.)
So, for example, I have one order that shows readings for equity of $1000, equity risk-per-trade of $10, a price difference of $26, and a position size of 0.38 Eth, for a total of $657. Nevertheless, the script bought 0.0005 Eth, and for some reason the user-menu is set to risking $1 per trade.
I'll post the whole script below - just bear in mind that I'm not worried about the entry criteria and other bits and pieces, so much as understanding why the script doesn't buy the correct position size.
Thanks in advance for your time.
Code: Select all
//@version=5
strategy("My strategy",
overlay=true,
initial_capital=1000,
default_qty_type=strategy.cash,
commission_type=strategy.commission.cash_per_contract,
commission_value=0.005,
margin_long=0,
margin_short=0)
equity = strategy.initial_capital + strategy.netprofit
//User Inputs
i_mfilength = input.int(title="MFI Length", defval=14, step=1, group="Strategy Parameters", tooltip="MFI Length")
i_emalength = input.int(title="EMA Length", defval=200, step=1, group="Strategy Parameters", tooltip="Long Term MA")
// istoppercent = input.int(title="Stop Loss Percentage", defval=2, step=1, group="Strategy Parameters", tooltip ="Failsafe Stop Loss, Percentage Decline")
ibtstarttime = input.time(title="Start Backtest", defval=timestamp("01 Jan 2022 00:00 +0000"), group="Backtest Period")
ibtendtime = input.time(title="End Backtest", defval=timestamp("01 Jan 2099"), group="Backtest Period")
ireward_multi = input.float(title="Reward as a Multiple of Risk", defval=1.5, step=0.1, group="Strategy Parameters")
i_risk = input.float(title="Risk as Percentage of Equity", defval=1, step=0.1, group="Strategy Parameters")
i_mfiob = input.int(title="MFI Overbought Level", defval=80, step=1, minval = 1, maxval=100, group="Strategy Parameters")
i_mfios = input.int(title="MFI Oversold Level", defval=20, step=1, minval = 1, maxval = 100, group="Strategy Parameters")
idcl = input.int(title="Donchian Channels Length", defval=20, step=1, group="Strategy Parameters")
//Get Donchian Channels
lower = ta.lowest(idcl)
upper = ta.highest(idcl)
basis = math.avg(upper, lower)
//Get EMA
ema = ta.ema(close, i_emalength)
//Get MFI
mfi = ta.mfi(close, i_mfilength)
//Check Position Relative to Date Filter
//insidebtperiod = time >= ibtstarttime and time <= ibtendtime
//EMA, MFI and Donchian Buy Conditions
var float buyprice = 0.0
var bool dc_upsignal = false
var bool mfi_buysignal = false
if upper > upper[1] and (close > ema)
dc_upsignal := true
if close < ema
dc_upsignal := false
if mfi < i_mfios
mfi_buysignal := true
if close < ema
mfi_buysignal := false
mfi_sellsignal = mfi > i_mfiob
long_condition =
strategy.position_size == 0 and
mfi_buysignal
//dc_upsignal and
//close > upper [1]
//SL and TP
var float long_entryprice = 0.0
var float long_sl = na
var float long_tp = na
var float dc_lower_at_buy = na
long_diff = math.abs(long_entryprice - dc_lower_at_buy)
long_tp := long_entryprice + (ireward_multi * long_diff)
//Position Size
equitytorisk = equity * (i_risk/100)
pos_size = equitytorisk / long_diff
pos_size_cash = pos_size * long_entryprice
//percentloss = (long_diff/long_entryprice)*100
// ENTRY/EXIT
if long_condition
strategy.entry(id="Long", direction=strategy.long, qty=pos_size_cash)
dc_lower_at_buy := lower
if long_condition[1]
long_entryprice := open
//strategy.exit("EXIT LONG","LONG", stop=long_sl, limit=long_tp)
stop_condition = strategy.position_size > 0 ? close < dc_lower_at_buy : na
profit_condition = strategy.position_size > 0 ? close > long_tp : na
if profit_condition or stop_condition
strategy.close(id="Long", comment="Exit")
long_entryprice := na
dc_lower_at_buy := na
long_tp := na
// Plot Entry, TP and SL
//Plot Longs
plot(long_entryprice, color=color.lime, style=plot.style_linebr)
plot(dc_lower_at_buy, color=color.red, style=plot.style_linebr, offset=1, linewidth=2)
plot(long_tp, color=color.yellow, style=plot.style_linebr, linewidth=2)
//Plot Indicators
//Donchian Channels
u = plot(upper, "Donchian Channel Upper Limit", color=#2962FF)
l = plot(lower, "Donchian Channel Lower Limit", color=#2962FF)
plot(basis, "Donchian Channel Basis", color=#FF6D00)
fill(u, l, color=color.rgb(33, 150, 243, 95), title="Background")
plot(ema, title="EMA", color=color.red, linewidth=2)
plot(equity, "equity", color=color.black)
plot(equitytorisk, "Equity Risked", color=color.purple)
plot(long_diff, "Price Difference, Entry and Exit", color = color.blue)
//plot(percentloss, "Percentage Loss", color = color.red)
plot(pos_size, "Position Size", color = color.black)
plot(pos_size_cash, "Position Size in Cash", color = color.green)