Я вижу ошибку 'Cannot create an order with negative quantity'

Эта ошибка появляется, когда стратегия вычисляет размер своего входа как процент от своего капитала. Если капитал падает ниже 0, размер позиции также становится отрицательным, что невозможно и приводит к ошибке.

Лучший способ исправить эту проблему — конвертировать стратегию в Pine Script v6. В Pine v6 стратегия по умолчанию применяет ограничения на размер позиции. Если капитал стратегии начинает падать слишком сильно, существующие позиции будут принудительно ликвидированы маржинальными вызовами, а если средства полностью закончатся, стратегия не будет пытаться создавать новые ордера с отрицательным количеством, избегая этой ошибки.

Если вы хотите узнать больше об источнике этой ошибки и о том, как избежать ее в более ранних версиях Pine, ознакомьтесь с текстом ниже.

Данная ошибка появляется в том случае, если баланс стратегии ушёл в минус и итоговое количество контрактов, рассчитанное для функций 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 для управления рисками. Подробнее об этом можно прочитать в нашем руководстве пользователя.