Я вижу ошибку 'Cannot create an order with negative quantity'
Данная ошибка появляется в том случае, если баланс стратегии ушёл в минус и итоговое количество контрактов, рассчитанное для функций strategy.entry() или strategy.order() является целочисленным отрицательным значением (qty < 0). Её можно избежать, поменяв параметры стратегии в её настройках или напрямую в исходном коде.
Причины появления ошибки
Рассмотрим скрипт, в котором объём заявки считается как процент от баланса (настройка strategy_percent_of_equity) и на каждом баре вызывается функция для входа в позицию strategy.entry():
//@version=5
strategy("negative_qty", default_qty_type = strategy.percent_of_equity)
strategy.entry("Short", strategy.short)
plot(strategy.equity)
При добавлении скрипта на график NASDAQ:AAPL с таймфреймом 1D скрипт падает с ошибкой времени выполнения:
Cannot create an order with negative quantity.
Current qty_type is percent_of_equity and equity is less than 0
Для понимания причины возникновения данной ошибки следует построить график баланса, используя переменную strategy.equity, и добавить ограничение на вызов функции strategy.entry() с помощью оператора условия. Так функция для входа в позицию не будет вызываться на каждом баре (и вызывать дополнительный пересчет параметров, среди которых значение qty) и скрипт посчитается успешно:
//@version=5
strategy("negative_qty", default_qty_type = strategy.percent_of_equity)
if strategy.equity > 0
strategy.entry("Short", strategy.short)
hline(0, "zero line", color = color.black, linestyle = hline.style_dashed)
plot(strategy.equity, color = color.black, linewidth = 3)
На открытии второго бара (bar_index = 1) стратегия входит в короткую позицию. Но с ростом стоимости AAPL прибыль (значение переменной strategy.openprofit) от открытой короткой позиции Short падает, и в конце концов баланс стратегии (strategy.equity = strategy.initial_capital + strategy.netprofit + strategy.openprofit) становится отрицательным.
Количество контрактов, которое рассчитывается движком стратегии вычисляется как qty = (order size * equity / 100) / close. Участок, на котором баланс стратегии переходит в отрицательные значения, можно отобразить следующим образом:
//@version=5
strategy("negative_qty", default_qty_type = strategy.percent_of_equity)
if strategy.equity > 0
strategy.entry("Short", strategy.short)
hline(0, "zero line", color = color.black, linestyle = hline.style_dashed)
plot(strategy.equity, color = color.black, linewidth = 3)
equity_p = 1 // percents of equity order size value (1% is default)
qty = (equity_p * strategy.equity / 100) / close
if qty <= -1
var l1 = label.new(bar_index, strategy.equity, text = "Negative qty_value at \n bar index: " + str.tostring(bar_index) + ".\n" + "Order size: " + str.tostring(math.round(qty)), color = color.white)
var l2 = label.new(bar_index - 1, strategy.equity[1], text = "Order size : " + str.tostring(math.round(qty[1])), color = color.white)
var l3 = label.new(bar_index - 2, strategy.equity[2], text = "Order size: " + str.tostring(math.round(qty[2])), color = color.white)
bgcolor(qty > -1 ? color.green : color.red)
На скриншоте изображен лейбл, расположенный на участке отрицательного баланса, на котором результирующее количество контрактов равно - 2. Число контрактов на зеленом участке >= 0:
В случае, если при расчете стратегии вызвать strategy.entry() на баре с отрицательным балансом (и на котором число контрактов является отрицательным), вычисление стратегии останавливается с ошибкой.
Как её избежать?
Как правило, в корректно реализованной стратегии данная ошибка не появляется. Чтобы избежать ошибки, стратегия должна использовать условия для входа и выхода из позиции, стопы и, как последний рубеж, маржу.
В случае, если ошибка появляется, корректными методами для отладки стратегии являются:
1. Использование маржинального плеча через соответствующие настройки в окне параметров стратегии или через параметры margin_long, и margin_short в функции strategy(), чтобы закрыть части позиции, в случае, если у стратегии недостаточно средств для ее поддержания. Подробнее про этот функционал можно узнать в статье нашего Руководства Пользователя или посте в блоге.
//@version=5
strategy("", default_qty_type = strategy.percent_of_equity, default_qty_value = 10, margin_long = 100, margin_short = 100)
longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28))
if (longCondition)
strategy.entry("Long", strategy.long)
shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28))
if (shortCondition)
strategy.entry("Short", strategy.short)
2. Проверка значений баланса на то, выше ли они нуля, перед вызовами функций strategy.entry() и strategy.order() или дополнительное переопределение количества контрактов для входа, например:
//@version=5
strategy("", default_qty_type = strategy.percent_of_equity, default_qty_value = 10)
if strategy.equity > 0
strategy.entry("Short", strategy.short) // enter at 10 % of currently available equity
else
strategy.entry("Long", strategy.long, qty = 1) // Reverse position with fixed contract size
3. Использование переменных категории strategy.risk для управления рисками. Подробнее об этом можно прочитать в нашем руководстве пользователя.