Pokazuje się błąd „Nie można utworzyć zlecenia z ujemną ilością”

Ten błąd pojawia się, gdy strategia oblicza wielkość swojego wejścia jako procent kapitału. Jeśli kapitał spadnie poniżej 0, wielkość pozycji również staje się ujemna, co jest niemożliwe i powoduje błąd podczas wykonywania.

Najlepszym sposobem na rozwiązanie tego problemu jest przekonwertowanie strategii na Pine Script v6. W Pine v6 strategia domyślnie nakłada ograniczenia na wielkość pozycji. Jeśli kapitał strategii zacznie spadać zbyt mocno, istniejące pozycje zostaną wymuszone do likwidacji przez wezwania do uzupełnienia depozytu, a jeśli środki całkowicie się wyczerpią, strategia nie będzie próbowała tworzyć nowych zleceń z ujemną ilością, unikając tego błędu.

Jeśli chcesz dowiedzieć się więcej o źródle tego błędu i jak go uniknąć we wcześniejszych wersjach Pine, zapoznaj się z poniższym tekstem.

Błąd występuje, gdy kapitał strategii staje się ujemny, a całkowita liczba kontraktów obliczona dla funkcji strategy.entry() lub strategy.order() jest ujemna. Można tego uniknąć, dostosowując ustawienia strategii w menu Właściwości lub bezpośrednio zmieniając logikę strategii.

Źródło błędu

Przyjrzyjmy się skryptowi, w którym wielkość zlecenia jest obliczana jako procent kapitału, albo poprzez ustawienie Wielkości Zlecenia w ustawieniach strategii, albo za pomocą stałej strategy_percent_of_equity w kodzie źródłowym Pine strategii. Na każdej świecy wywoływana jest funkcja strategy.entry() w celu wejścia w pozycję:

//@version=5
strategy("negative_qty", default_qty_type = strategy.percent_of_equity)

strategy.entry("Short", strategy.short)
plot(strategy.equity)

Po dodaniu skryptu do wykresu NASDAQ:AAPL dla przedziału czasowego 1D, skrypt ulega awarii z błędem wykonania:

Nie można utworzyć zlecenia z ujemną ilością. 
Obecny qty_type to percent_of_equity, a kapitał jest mniejszy niż 0

Aby zrozumieć przyczynę tego błędu, należy wykreślić kapitał za pomocą zmiennej strategy.equity i dodać ograniczenie na wywołanie funkcji strategy.equity() za pomocą dowolnego operatora warunkowego. W ten sposób funkcja wejścia w pozycję nie będzie wywoływana na każdej świecy (i nie spowoduje dodatkowego przeliczenia parametrów, w tym wartości qty), a skrypt zostanie pomyślnie obliczony:

//@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) 

Na otwarciu drugiej świecy (bar_index = 1), strategia wchodzi w pozycję krótką. Ale wraz ze wzrostem wartości AAPL, zysk (wartość zmiennej strategy.openprofit) z otwartej pozycji krótkiej Short gwałtownie spada, a ostatecznie kapitał strategii (strategy.equity = strategy.initial_capital + strategy.netprofit + strategy.openprofit) staje się ujemny.

Liczba kontraktów obliczana przez silnik strategii jest obliczana jako qty = (wielkość zlecenia * kapitał / 100) / close. Obszar, w którym kapitał strategii staje się ujemny, można wyświetlić w następujący sposób:

//@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  // procent kapitału (domyślna wartość to 1%)
qty = (equity_p * strategy.equity / 100) / close 

if qty <= -1 
    var l1  = label.new(bar_index, strategy.equity, text = "Ujemna wartość qty na \n świecy o indeksie: " + str.tostring(bar_index) + ".\n" +  "Wielkość zlecenia: " + str.tostring(math.round(qty)), color = color.white) 
    var l2 = label.new(bar_index - 1, strategy.equity[1], text = "Wielkość zlecenia: " + str.tostring(math.round(qty[1])), color = color.white)
    var l3 = label.new(bar_index - 2, strategy.equity[2], text = "Wielkość zlecenia: " + str.tostring(math.round(qty[2])), color = color.white)

bgcolor(qty > -1 ? color.green : color.red)

Na zrzucie ekranu widać etykietę znajdującą się w sekcji ujemnego kapitału, gdzie wynikowa liczba kontraktów wynosi -2. Liczba kontraktów w zielonej sekcji jest >= 0:

Jeśli podczas obliczania strategii funkcja strategy.entry() jest wywoływana na świecy z ujemnym kapitałem (i na której liczba kontraktów jest ujemna), obliczenia strategii zatrzymują się z błędem.

Jak to naprawić?

Z reguły ten błąd nie pojawia się w poprawnie zaimplementowanej strategii. Aby uniknąć błędów, strategia powinna używać warunków wejścia i wyjścia z pozycji, stopów oraz marginesu.

Jeśli wystąpi błąd, poprawne metody debugowania strategii to:

1. Użycie dźwigni marginesowej (Margines dla pozycji długich/krótkich w Właściwościach strategii lub parametry margin_long i margin_short w funkcji strategy()). Jeśli zostanie określony, część pozycji zostanie automatycznie zlikwidowana, jeśli strategia nie będzie miała wystarczającego kapitału do jej utrzymania. Więcej na temat tej funkcjonalności można przeczytać w artykule w naszej Instrukcji obsługi lub w wpisie na blogu.

//@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. Sprawdzenie wartości kapitału, czy jest większa od zera, przed wywołaniem funkcji strategy.entry() lub strategy.order() lub dodatkowe zdefiniowanie liczby kontraktów wejściowych.

//@version=5
strategy("", default_qty_type = strategy.percent_of_equity, default_qty_value = 10)

if strategy.equity > 0 
    strategy.entry("Short", strategy.short)  // wejście na 10% dostępnego kapitału
else 
    strategy.entry("Long", strategy.long, qty = 1) // Odwrócenie pozycji z ustaloną wielkością kontraktu


3. Użycie zmiennych z kategorii strategy.risk do zarządzania ryzykiem. Więcej na ten temat można przeczytać w naszej Instrukcji obsługi.