В прошлой главе вы считали по данным одной свечи. Для изменения закрытия нужны две: текущая и предыдущая. Здесь вы свяжете их.

Программа та же, свеча меняется

На демонстрационных данных PyneCore идёт по свечам в хронологическом порядке. main() работает с первой, затем второй и так далее. close каждый раз означает закрытие обрабатываемой свечи.

Поэтому один вызов plot(close, "Close") рисует целую линию. Одно выполнение добавляет точку, последовательность свечей образует всю линию.

Строка midpoint = (high + low) / 2 тоже выполняется заново на каждой свече. Присваивание пересчитывает её середину. Имя переменной сохраняется, значение может меняться.

Порядок обработки обеспечивает среда исполнения. Писать собственный цикл для всего графика не нужно.

Обращение к прошлому в квадратных скобках

close[1] означает закрытие одной свечой ранее. Число в скобках задаёт глубину обращения.

ВыражениеКакое закрытие?
closeОбрабатываемой свечи
close[0]Тоже обрабатываемой свечи
close[1]Одной свечой ранее
close[2]Двумя свечами ранее

Если три последовательных дневных закрытия равны 100, 103 и 101, на третьей свече close равно 101, close[1] равно 103, close[2] равно 100.

Тогда close - close[1] означает 101 - 103, то есть −2. Это разница последовательных закрытий. close - open сравнивает открытие и закрытие одной свечи. Расчёты отвечают на разные вопросы.

Глубина измеряется свечами, не календарными днями. Выходные или торговый праздник могут отделять предыдущую дневную свечу несколькими днями.

У собственного значения тоже есть история

История встроенных цен уже доступна. Для обращения к собственному расчёту пометьте переменную Series:

midpoint: Series[float] = (high + low) / 2

После двоеточия идёт аннотация типа. float обозначает число с возможной дробной частью. Series[float] также просит сохранять историю переменной по свечам.

Присваивание всё так же происходит на каждой свече. midpoint является текущим результатом, midpoint[1] значением, сохранённым на предыдущей свече. Имя Series импортируется из pynecore.

Два вида изменений на графике

Создайте history_change.py в папке scripts:

"""
@pyne edge
"""
from pynecore import Series
from pynecore.lib import close, color, high, low, plot, script


@script.indicator("Changes Between Candles", overlay=False)
def main():
    midpoint: Series[float] = (high + low) / 2
    close_change = close - close[1]
    midpoint_change = midpoint - midpoint[1]
    plot(close_change, "Close change", color=color.blue)
    plot(midpoint_change, "Midpoint change", color=color.orange)

Сохраните, выберите Run Pyne code и данные demo. В отдельной панели появятся две линии. Синяя показывает изменение закрытия, оранжевая изменение середины. Положительная точка означает рост относительно прошлой свечи.

Рядом с history_change.py график PyneIDE показывает две линии изменений.
Изменения закрытия и вычисленной середины между свечами в отдельной панели.

Наведите указатель на свечу. Значения графика относятся к моменту под указателем; отдельно выбирать его в файле не требуется.

Что происходит на самой первой свече?

У первой свечи нет предыдущей в файле данных. Поэтому close[1] является отсутствующим значением na, сокращением от «not available».

Отсутствующая цена не равна нулю. Результат close - close[1] тоже отсутствует, и программа не рисует допустимое изменение на первой свече. Это верно: разницу двух свечей нельзя вычислить по одной.

Вызов na(value) проверяет отсутствие значения. Условия вы изучите в главе об условиях и отметках. Пока не пытайтесь исправить отсутствующую точку в начале графика, считая цену нулевой.

Будущие свечи эта запись не открывает. close[-1] тоже не означает следующее закрытие. Решение может использовать только данные, доступные на этом выполнении.

Попробуйте самостоятельно

Измените синюю линию: сравнивайте закрытие с закрытием пятью свечами ранее. Укажите расстояние и в названии линии.

Предскажите, на скольких начальных свечах будет отсутствовать результат.

Решение
close_change = close - close[5]
plot(close_change, "Five-candle change", color=color.blue)

На первых пяти свечах нет закрытия пятью свечами ранее. На шестой уже есть: закрытие первой свечи файла.

Оранжевая линия не изменится. Для обоих изменений на пяти свечах нужно также изменить midpoint[1].

Проверьте расчёт

Выберите три последовательные свечи. Запишите закрытия и вручную вычислите односвечное изменение для второй и третьей. Синяя линия должна показывать те же значения. При расхождении сначала проверьте моменты и глубину обращения.

Дополнительное задание: сохранённое значение вместо истории

Одно предыдущее значение можно использовать, сохранив его для следующей свечи. Для этого служит Persistent, который изучается в главе о памяти программы. Задание можно выполнить после неё.

Перепишите history_change.py без close[1] и midpoint[1]. Две персистентные переменные должны хранить прошлые закрытие и середину. Линии должны совпадать с оригиналом, а первое изменение оставаться отсутствующим.

Продумайте порядок: когда читать сохранённое значение и когда заменять текущим?

Решение

Замените импорт Series на Persistent:

from pynecore import Persistent

Добавьте na в импорт pynecore.lib. Сохраните начальную метку и настройки индикатора, замените main():

def main():
    previous_close: Persistent[float] = na
    previous_midpoint: Persistent[float] = na
    midpoint = (high + low) / 2
    close_change = close - previous_close
    midpoint_change = midpoint - previous_midpoint
    plot(close_change, "Close change", color=color.blue)
    plot(midpoint_change, "Midpoint change", color=color.orange)
    previous_close = close
    previous_midpoint = midpoint

Начальные значения обеих переменных равны na: на первой свече предыдущей цены нет. Первая разность тоже отсутствует. В конце функции сохраняем текущие значения для расчёта на следующей свече.

Если поместить previous_close = close перед вычитанием, из текущего закрытия вычтется оно само и получится ноль. Здесь порядок обновления контролируете вы.

Для обращения на одну свечу назад подходят оба способа. Квадратные скобки короче и позволяют напрямую обратиться на несколько свечей назад. Две переменные сохраняют только последние записанные цены.

Запустите оба варианта на одних данных и сравните линии на нескольких свечах.