Набор кода трейдера — Python и Pine Script
Шесть фрагментов для копирования: четыре на Python (загрузка журнала CSV, показатели, кривая капитала с просадкой и расчёт объёма по ATR) и два на Pine Script (дневной диапазон относительно ATR с оповещением и торговые окна плана на графике). Все они — АНАЛИТИЧЕСКИЕ инструменты: считают, строят графики и напоминают; не создают сигналы покупки/продажи и не принимают решения — это задача плейбука. Идентификаторы и имена API остаются на английском для соответствия документации pandas и Pine Script; комментарии и сообщения переведены на русский. Такой подход сохраняет техническую совместимость, о которой говорит мастерская ИИ в промптах для работы с кодом; пояснения на языке курса шаг за шагом показывают использование. Среда: установка Python и первые запуски рассматриваются в 11.8; заголовки столбцов журнала — в приложении F.
- Инструменты, а не стратегии: код считает показатели по ВАШИМ данным и следит за ВАШИМ планом. Граница та же, что в разделе «чего ИИ не делает» приложения H, и по тем же причинам
- Единый формат данных: фрагменты Python читают заголовки таблицы журнала (приложение F); доля прибыльных сделок включает безубыточные в знаменатель, а матожидание использует чистый результат. Определения совпадают с промптом P5
- Pine Script без lookahead: S5 получает дневные данные с
lookahead=barmerge.lookahead_off; S6 вообще не обращается к старшему таймфрейму (только функцияtime). Отсутствие lookahead не доказывает отсутствие перерисовки: описание S5 объясняет историю и работу в реальном времени. Именно такие ловушки ищет проверка кода промптом P3 - Расчётчик округляет объём ВНИЗ: при переводе риска в лоты округление вверх систематически превышает плановый риск. Одна строка кода отделяет 1% от «около 1%»
Перед запуском: три правила
- Сначала прочитайте код. Каждый фрагмент намеренно короткий: нужно понимать каждую строку. Меняйте непонятный код с помощью проверки P3, а не догадок; для кода из форумов и чатов правило вдвойне важно.
- Данные поступают из файлов; решения из кода не выходят. Скрипты читают экспорт журнала формата приложения F и явно заданные параметры. На выходе — числа и графики для недельного обзора. Выводы делаете вы по процедуре аудита 15.10 с учётом размера выборки, зависимости сделок и неопределённости результата.
- Среда из 11.8: Python 3.11 или новее с
pandasиmatplotlib(установка и первый скрипт описаны там); S1–S4 повторно запущены 17 сентября 2026 на Python 3.12.10, pandas 3.0.5 и matplotlib 3.11.1. Другие версии не тестировались. Pine Script вставляйте в редактор индикаторов платформы; оба используют версию 6.
Минимальный запуск: в среде Python 3.11+ проверьте версию командой python --version, затем установите пакеты командой python -m pip install pandas==3.0.5 matplotlib==3.11.1, сохраните S1+S2+S3 как analiza_dziennika.py , а тестовый CSV — как dziennik.csv, затем запустите python analiza_dziennika.py. S4 нужна только стандартная библиотека. S5 и S6 вставляйте в Pine Editor отдельно. Оба фрагмента Pine проверены по документации v6; они не компилировались, оповещения в TradingView не тестировались.
S1 · Загрузка журнала CSV
Python 3 · pandasОснова для S2 и S3: читает экспорт таблицы приложения F, проверяет заголовки и число полей, затем очищает столбец r_net . Повторяющиеся имена столбцов, пустой заголовок, избыток или недостаток полей останавливают импорт: скрипт не выбирает из двух столбцов результатов и не переносит данные в индекс. Пустое поле обозначайте разделителем, например ;A+;;0; обрезанная строка — другой случай. Задайте разделитель и десятичный знак для варианта CSV (PL: точка с запятой и запятая; EN: запятая и точка), а также кодировку: генератор приложения F использует UTF-8; «CSV UTF-8» из Excel тоже читается как UTF-8. Старому экспорту в польской кодировке может требоваться cp1250. Проверьте формат сохранения: язык интерфейса сам по себе не определяет кодировку. Пустой r_net и пустой close_time_utc означают ещё не закрытую сделку (она пропускается); время закрытия без результата означает неполную запись и останавливает расчёт. Непустое значение, не читаемое как число (включая «NA» и прочерк), останавливает скрипт с номером записи. Так же обрабатывается закрытая сделка без времени закрытия в формате приложения F (2026-07-08 13:15): иначе порядок кривой пришлось бы угадывать.
import pandas as pd
CSV_PATH = "dziennik.csv" # экспорт журнала (структура приложения F)
CSV_SEP = ";" # ";" для CSV с польскими региональными настройками, "," для EN
DECIMAL = "," # "," для CSV с польскими региональными настройками, "." для EN
ENCODING = "utf-8-sig" # генератор приложения F записывает UTF-8 (BOM обрабатывается); для старого CSV в польской кодировке может понадобиться "cp1250"
REQUIRED = ["r_net", "setup", "setup_class", "error_code", "close_time_utc"]
# Прочитать локальный файл и проверить его структуру ДО создания DataFrame.
# pandas.read_csv может переименовать повторяющиеся заголовки или вывести индекс из лишних полей.
import csv
try:
with open(CSV_PATH, encoding=ENCODING, newline="") as source:
reader = csv.reader(source, delimiter=CSV_SEP, strict=True)
header = next(reader, None)
if not header:
raise SystemExit("Невозможно прочитать CSV: заголовок пуст.")
if any(not name or name != name.strip() for name in header):
raise SystemExit("Пустое имя столбца или имя с пробелами по краям — исправьте заголовок CSV.")
duplicates = sorted({name for name in header if header.count(name) > 1})
if duplicates:
raise SystemExit(f"Повторяющиеся столбцы: {duplicates} — устраните повторы в журнале.")
rows, record_indexes = [], []
for index, row in enumerate(reader):
if not row: # полностью пустая запись CSV
continue
if len(row) != len(header):
raise SystemExit(f"Запись {index + 1}: ожидалось {len(header)} полей, получено {len(row)} "
f"— проверьте разделители и кавычки; ни одно поле не было отброшено.")
rows.append(row)
record_indexes.append(index)
df = pd.DataFrame(rows, columns=header, index=record_indexes, dtype="string").replace("", pd.NA)
except UnicodeDecodeError:
raise SystemExit(f"Невозможно декодировать {CSV_PATH} как {ENCODING} — проверьте UTF-8 или старую кодировку cp1250.") from None
except (OSError, csv.Error) as exc:
raise SystemExit(f"Невозможно прочитать {CSV_PATH}: {exc}") from None
missing = [c for c in REQUIRED if c not in df.columns]
if missing:
raise SystemExit(f"Отсутствуют столбцы: {missing} — сверьте заголовки с приложением F и настройкой CSV_SEP.")
raw = df["r_net"] # пустой результат допустим, только если время закрытия тоже пусто
txt = raw.astype("string").str.strip().str.replace(DECIMAL, ".", regex=False) # разбираем столбец сами: одна некорректная ячейка не должна скрыть читаемые
r = pd.to_numeric(txt, errors="coerce").astype("Float64") # избежать переполнения целых чисел в последующих суммах
r = r.where(r.abs() != float("inf")) # inf тоже не является допустимым результатом в единицах R
invalid = raw.notna() & r.isna() # заполнено, но не читается как число
if invalid.any():
raise SystemExit(f"Некорректный r_net в записях {(df.index[invalid] + 1).tolist()} "
f"(запись 1 = первая строка под заголовком) — проверьте значения и DECIMAL; "
f"NA, прочерки и бесконечность не являются числами.")
blank = df.isna().all(axis=1) # вся строка пуста = неиспользованная строка листа (экспорт всего листа XLSX), а не сделка
df, r = df[~blank], r[~blank]
has_close = df["close_time_utc"].fillna("").str.strip().ne("")
incomplete = r.isna() & has_close
if incomplete.any():
raise SystemExit(f"Отсутствует r_net у закрытых записей {(df.index[incomplete] + 1).tolist()} "
f"— заполните чистый результат перед расчётом показателей.")
open_trades = int(r.isna().sum())
df = df.assign(r_net=r).dropna(subset=["r_net"]) # индекс сохранён = номера записей для сообщения ниже
# для кривой капитала и просадки нужен хронологический порядок (приложение F: по времени закрытия); закрытая сделка с нечитаемым временем закрытия останавливает скрипт
close_text = df["close_time_utc"].fillna("").str.strip()
has_time = close_text.str.fullmatch(r"\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:\d{2})?")
closed = pd.to_datetime(close_text.where(has_time), errors="coerce", format="ISO8601", utc=True) # приложение F записывает 2026-07-08 13:15; фиксированный формат делает проверку независимой от порядка строк, utc=True предотвращает сбой из-за случайного суффикса "Z"/"+00:00"
if closed.isna().any():
raise SystemExit(f"Нечитаемое close_time_utc в записях {(df.index[closed.isna()] + 1).tolist()} "
f"— каждой закрытой сделке нужно время закрытия в формате приложения F (2026-07-08 13:15); исправьте журнал, а не скрипт.")
df = df.assign(_t=closed).sort_values("_t", kind="stable").drop(columns="_t").reset_index(drop=True)
print(f"Загружено закрытых сделок: {len(df)} (пропущено строк: {open_trades} — нет времени закрытия и r_net).")
Результат: DataFrame df, готовый к следующим фрагментам, отсортирован по времени закрытия (в этом порядке считаются кривая и просадка), плюс число пропущенных открытых сделок. Пустая строка — полностью пустая запись, как при экспорте целого листа XLSX: скрипт их не считает. Строка с данными, но без результата и времени закрытия пропускается как незакрытая; закрытая запись без результата останавливает скрипт. Если он остановился со списком записей, исправляйте строки журнала, а не скрипт. Если затронут весь столбец, проверьте также константу DECIMAL . Нумерация записей начинается после заголовка и включает пустые записи; поле в кавычках может содержать разделитель или перевод строки и оставаться одной записью. Каждая сделка должна встречаться один раз: перед объединением экспортов проверьте идентификаторы trade_id — S1 не удаляет дубликаты истории. Даты без времени недостаточно для восстановления порядка. Время без часового пояса считается UTC; явное смещение ISO 8601 пересчитывается в UTC. При одинаковом времени сохраняется порядок записей: задайте его в журнале, поскольку он влияет на траекторию просадки.
S2 · Показатели журнала
Python 3 · pandasТе же определения, что у промпта P5 и панели таблицы: доля прибыльных сделок включает безубыточные в знаменатель; профит-фактор возвращает сообщение вместо деления на ноль; матожидание — среднее чистого R (r_net); просадка считается по накопленной кривой с началом 0 R (первый убыток уже является просадкой, как в формуле таблицы F). Запускайте после S1. Определения общие, но обработка ошибок отличается от P5: S1 прекращает анализ при некорректном результате закрытой сделки, а P5 требует пропустить и посчитать её. Сравнивайте результаты, лишь установив, какие сделки включены в обе выборки.
import math
def metrics(r):
"Основные показатели журнала по ряду чистых результатов в единицах R.\n Определения (как на панели приложения F):\n - доля прибыльных сделок: сделки с r > 0 среди ВСЕХ допустимых сделок (безубыточные остаются в знаменателе)\n - профит-фактор: сумма положительных r, делённая на abs(сумму отрицательных r)\n - математическое ожидание: среднее арифметическое r (после издержек)\n - максимальная просадка: наибольшее снижение накопленной кривой R от её текущего максимума;\n кривая начинается с 0 R (поэтому первый убыток -1 R уже даёт просадку 1 R)"
n = len(r)
if n == 0:
raise SystemExit("Нет допустимых сделок — нечего измерять.")
try:
r = r.astype(float)
except (TypeError, ValueError):
raise SystemExit("Для расчёта показателей нужны числовые чистые значения R — сначала выполните S1.") from None
if not r.map(math.isfinite).all():
raise SystemExit("Для расчёта показателей нужны конечные чистые значения R — сначала выполните S1.")
wins = r[r > 0]
losses = r[r < 0]
equity = r.cumsum()
peak = equity.cummax().clip(lower=0) # приложение F: MAX(0; текущий максимум)
drawdown = peak - equity
try:
total = math.fsum(r)
pf_value = None if losses.empty else math.fsum(wins) / abs(math.fsum(losses))
except (OverflowError, ValueError, ZeroDivisionError):
raise SystemExit("Превышен числовой диапазон — проверьте значения R; показатели не рассчитаны.") from None
if (not equity.map(math.isfinite).all() or not drawdown.map(math.isfinite).all()
or (pf_value is not None and not math.isfinite(pf_value))):
raise SystemExit("Превышен числовой диапазон — проверьте значения R; показатели не рассчитаны.")
pf = "в выборке нет убыточных сделок" if pf_value is None else round(pf_value, 2)
return {
"trades": n,
"win_rate": round(len(wins) / n, 3),
"profit_factor": pf,
"expectancy_R": round(total / n, 3),
"sum_R": round(total, 2),
"max_drawdown_R": round(drawdown.max(), 2),
}
for key, value in metrics(df["r_net"]).items():
print(f"{key:>16}: {value}")
Результат: шесть показателей для недельного обзора; без убытков PF является сообщением, а не числом. При выходе за числовой диапазон скрипт останавливает анализ, а не возвращает inf, NaN или мнимую нулевую просадку. WR = 0.4 означает 40%. PF считается в R, а не PLN; при переменном денежном риске результаты могут отличаться. Издержки уже включены в r_net — S2 не вычитает их снова. Одно среднее и прохождение 20 или 50 сделок не дают оценки преимущества. Определения панели — в приложении F, план выбора выборки, издержек и валидации — в приложении N.
S3 · Кривая капитала и просадка
Python 3 · pandas + matplotlibСтроит накопленную кривую R с просадкой от пика под ней и сохраняет PNG рядом с CSV, заданным CSV_PATH (S1), независимо от каталога запуска скрипта. Кривая показывает порядок результатов и скопления убытков, скрытые итоговыми числами. Это сумма R, а не баланс в PLN или средства в процентах: при переменном денежном риске она не воспроизводит изменения баланса. График не учитывает пополнения, выводы и результат открытых позиций. Запускайте после S1.
import math
import matplotlib.pyplot as plt
from pathlib import Path
if len(df) == 0:
raise SystemExit("Нет закрытых сделок — нечего отображать.")
equity = df["r_net"].astype(float).cumsum()
drawdown = equity.cummax().clip(lower=0) - equity # то же определение, что в S2 и приложении F (кривая начинается с 0 R)
if not equity.map(math.isfinite).all() or not drawdown.map(math.isfinite).all():
raise SystemExit("Превышен числовой диапазон — проверьте значения R; график не сохранён.")
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 6), sharex=True,
gridspec_kw={"height_ratios": [3, 1]})
x = [0, *(equity.index + 1)] # сделка 0 = начальная точка 0 R, от которой измеряется просадка
ax1.plot(x, [0.0, *equity.values])
ax1.set_ylabel("капитал (R)")
ax1.set_title("Кривая капитала — накопленный чистый результат R")
ax1.grid(True, alpha=0.3)
ax2.fill_between(x, [0.0, *(-drawdown.values)], 0, alpha=0.5)
ax2.set_ylabel("просадка (R)")
ax2.set_xlabel("номер сделки")
ax2.grid(True, alpha=0.3)
fig.tight_layout()
PNG_PATH = Path(CSV_PATH).with_name("equity_curve.png") # рядом с файлом журнала независимо от рабочего каталога
fig.savefig(PNG_PATH, dpi=150)
plt.close(fig)
print(f"Сохранено: {PNG_PATH}")
Результат: файл equity_curve.png рядом с журналом; кривая начинается с 0 R (сделка 0), откуда измеряется просадка. Нижняя панель показывает просадку накопленного R от пика по всей истории (с началом 0 R, как в S2 и таблице F), а не недельный убыток. Недельный лимит плана (приложение E) проверяйте отдельно по неделям, с указанными в плане единицей и правилом сброса.
Сохраните как dziennik.csv (UTF-8) рядом с объединённым скриптом S1+S2+S3 и запустите. Файл содержит лишь нужные S1 столбцы; полный экспорт приложения F (26 столбцов) загружается так же. Последняя строка — открытая сделка (пустой r_net); первые две закрытые — убыточные, поэтому просадка считается от 0 R.
trade_id;close_time_utc;setup;setup_class;r_net;error_code 2026-041;2026-07-08 13:15;wybicie-azja-londyn;A+;-1,00;5 2026-042;2026-07-09 16:40;powrot-do-sredniej;B;-1,08;3 2026-043;2026-07-10 09:05;wybicie-azja-londyn;A+;1,83;0 2026-044;2026-07-13 12:20;wybicie-azja-londyn;B;0,00;0 2026-045;2026-07-14 14:30;powrot-do-sredniej;C;2,40;0 2026-046;;wybicie-azja-londyn;B;;
Ожидаемый вывод (Python 3.12.10, pandas 3.0.5, matplotlib 3.11.1; запуск 17 сентября 2026):
Загружено закрытых сделок: 5 (пропущено строк: 1 — нет времени закрытия и r_net).
trades: 5
win_rate: 0.4
profit_factor: 2.03
expectancy_R: 0.43
sum_R: 2.15
max_drawdown_R: 2.08
Сохранено: equity_curve.png
Проверка вручную: прибыль 1.83 + 2.40 = 4.23 R, убытки 1.00 + 1.08 = 2.08 R → PF 2.03; итог 2.15 R / 5 = 0.43 R; кривая −1.00 → −2.08 → −0.25 → −0.25 → 2.15 при начальном пике 0 R → просадка 2.08 R. Без точки 0 R получилось бы 1.08 R — различие из определения приложения F. Вывод относится к этому файлу и указанным версиям. При отличии последовательно проверьте данные (разделитель, десятичный знак, кодировку, порядок строк), константы S1, код и версии пакетов.
S4 · Расчёт объёма по ATR
Python 3 · стандартная библиотекаОбъём в лотах для стопа k × ATR: сумма риска берётся из капитала и процента, расстояние — из ATR, объём округляется ВНИЗ до шага лота вашего счёта (параметры lot_step и min_lot , оба по умолчанию 0.01), чтобы ПЛАНОВЫЙ риск не превышал бюджет. Реальный убыток может быть больше: расчёт не учитывает проскальзывание, гэпы через стоп, спред, комиссию и своп. Капитал и цена пипса должны быть в одной валюте счёта; максимальный объём и маржу проверьте по спецификации отдельно. Введите ATR в пипсах (EURUSD 0.0080 → 80; USDJPY 0.80 → 80; размер пипса — в профиле пары, приложение B); цена пипса для 1 лота — в спецификации инструмента или в калькуляторе приложения C.
import math
from decimal import Decimal
from fractions import Fraction
def atr_position_size(capital, risk_pct, atr_pips, atr_mult, pip_value_per_lot,
lot_step=0.01, min_lot=0.01):
"Объём в лотах для стопа atr_mult × ATR.\n atr_pips: ATR в ПИПСАХ, а не в единицах цены (EURUSD ATR 0.0080 -> 80; USDJPY ATR 0.80 -> 80 — с учётом размера пипса пары).\n pip_value_per_lot: стоимость 1 пипса для 1.00 лота в валюте счёта\n (например, ~10 USD для EURUSD на счёте в USD — проверьте спецификацию инструмента).\n lot_step / min_lot: шаг и минимальный объём ВАШЕГО счёта (0.01 распространён, но не универсален).\n Округляет ВНИЗ до кратного lot_step, отсчитываемого от нуля. Арифметика Fraction\n сохраняет десятичные входные значения независимо от глобальной точности Decimal.\n Плановый риск не равен максимальному убытку: проскальзывание, гэпы, спред и своп в модель не входят."
inputs = (capital, risk_pct, atr_pips, atr_mult, pip_value_per_lot, lot_step, min_lot)
if any(isinstance(x, bool) or not isinstance(x, (int, float, Decimal)) for x in inputs):
raise ValueError("Используйте числовые значения, а не текст или логические значения (десятичные числа Python записываются с точкой).")
decimals = tuple(Decimal(str(x)) for x in inputs)
if not all(x.is_finite() and x > 0 for x in decimals):
raise ValueError("Все входные значения должны быть конечными положительными числами.")
c, p, a, k, v, step, minimum = map(Fraction, decimals)
if p > 100:
raise ValueError("risk_pct — процент капитала (1.0 = 1%).")
risk_amount = c * p / 100
sl_pips = a * k
lots = math.floor(risk_amount / (sl_pips * v * step)) * step
if lots < minimum:
return {"warning": "При этих lot_step и min_lot нет допустимого объёма в пределах бюджета риска."}
exact = {"risk_amount": risk_amount, "sl_pips": sl_pips,
"lots": lots, "planned_risk": lots * sl_pips * v}
try:
result = {key: float(value) for key, value in exact.items()}
except OverflowError:
raise ValueError("Входные значения превышают числовой диапазон результата.") from None
if not all(math.isfinite(value) and value > 0 for value in result.values()):
raise ValueError("Входные значения превышают числовой диапазон результата.")
return result # float для отображения; без дополнительного округления стопа или денежных значений
print(atr_position_size(capital=10_000, risk_pct=1.0,
atr_pips=80, atr_mult=1.5, pip_value_per_lot=10.0))
# {'risk_amount': 100.0, 'sl_pips': 120.0, 'lots': 0.08, 'planned_risk': 96.0}
Результат: лоты, округлённые вниз до шага, и соответствующий ПЛАНОВЫЙ денежный риск (в модели без издержек ≤ бюджета; фактический убыток может быть больше). Шаг отсчитывается от нуля; проверьте такую сетку объёма у счёта. Стоп и суммы больше не округляются: например, ATR 0.26 пипса × 1.25 даёт 0.325, а не 0.3 пипса. Вывод — значения float для чтения, а число шагов лота считается точными дробями. Минимальный шаг цены инструмента всё равно проверяется отдельно. Если меняете стоп под этот шаг, пересчитайте объём. Не ждите решения о входе: расчётчик отвечает «сколько», а не «входить ли».
S5 · Дневной диапазон и ATR с оповещением
Pine Script v6 · индикаторВнутридневной инструмент оценки волатильности: на текущих свечах показывает, какой процент дневного ATR рынок уже «израсходовал», и оповещает при пересечении порога — пора свериться с планом, а не гнаться за движением. Дневные данные получаются без lookahead (будущих значений); на исторических свечах request.security удерживает последнее подтверждённое дневное значение до конца следующего периода D; новый результат периода появляется на его последней внутридневной свече. В реальном времени получает формирующиеся диапазон и ATR текущей свечи D, поэтому прошлые показания могут измениться после перезагрузки (перерисовка). День — свеча D поставщика, а не календарный день Europe/Warsaw. ATR в знаменателе тоже меняется в течение дня; 100% не ограничивает движение цены. Метод не восстанавливает последовательные пересечения порога за сегодняшний день на исторических свечах.
//@version=6
indicator("Дневной диапазон и ATR (инструмент оценки обстановки)", overlay=false)
if not timeframe.isintraday
runtime.error("Используйте внутридневной график по времени с интервалом меньше 1D.")
atrLen = input.int(14, "Период ATR", minval=2)
warnPct = input.int(80, "Оповещать, когда дневной диапазон достигает % от ATR", minval=10, maxval=200)
// На истории: последнее подтверждённое значение D, обновляется В КОНЦЕ каждого периода D.
// В реальном времени: формирующиеся значения D; уже прошедшие показания реального времени могут перерисоваться после перезагрузки.
dayHigh = request.security(syminfo.tickerid, "D", high, lookahead=barmerge.lookahead_off)
dayLow = request.security(syminfo.tickerid, "D", low, lookahead=barmerge.lookahead_off)
dayAtr = request.security(syminfo.tickerid, "D", ta.atr(atrLen), lookahead=barmerge.lookahead_off)
rangePct = dayAtr > 0 ? 100.0 * (dayHigh - dayLow) / dayAtr : na
plot(rangePct, "Дневной диапазон в % от ATR", linewidth=2)
hline(100, "100% от ATR")
hline(warnPct, "Уровень оповещения", linestyle=hline.style_dotted)
alertcondition(ta.crossover(rangePct, warnPct),
title="Диапазон достиг % от ATR",
message="Дневной диапазон достиг заданного % от ATR — перечитайте план перед новым входом.")
Результат: панель под графиком и условие оповещения. Создайте его сами на платформе после добавления индикатора, выбрав «Диапазон достиг % от ATR». Используйте обычные внутридневные свечи по времени: данные Heikin Ashi/Renko могут отличаться. Отсутствие показания (na) означает недоступность ATR или данных, а не 0%. Условие требует перехода со значения ≤ порога к значению > порога; само пребывание выше не даёт нового оповещения. «Once Per Bar Close» ограничивает оповещения закрытием внутридневной свечи, но не подтверждает всю свечу D. Пересоздайте оповещение после изменения параметров. Не ждите сигнала направления: высокое значение говорит «движение уже произошло», а дальнейшее действие определяет плейбук.
S6 · Торговые окна плана на графике
Pine Script v6 · индикаторРаздел 3 плана (приложение E) на графике: подсвечивает часы, когда МОЖНО открывать позиции, и оповещает о закрытии окна. Установите точную зону IANA, объявленную в вашем плане, и введите его временные окна в той же зоне. Например, Europe/London учитывает GMT/BST по дате. В коде Europe/Warsaw сохранён как региональный пример (CET/CEST); замените это значение по умолчанию, если план использует другую зону. По умолчанию окна действуют с понедельника по пятницу; опция расширяет их на все дни. Подсветка подтверждает только время из плана, а не остальные условия входа. Используйте обычные внутридневные свечи по времени.
//@version=6
indicator("Торговые окна по плану", overlay=true)
if not timeframe.isintraday
runtime.error("Используйте внутридневной график по времени с интервалом меньше 1D.")
// Региональный пример: замените значение точной зоной IANA из вашего плана.
tz = input.string("Europe/Warsaw", "Зона IANA из плана")
win1 = input.session("0900-1200", "Окно 1")
win2 = input.session("1400-1700", "Окно 2")
weekdaysOnly = input.bool(true, "Только с понедельника по пятницу")
days = weekdaysOnly ? ":23456" : ":1234567"
inWin = not na(time(timeframe.period, win1 + days, tz)) or not na(time(timeframe.period, win2 + days, tz))
bgcolor(inWin ? color.new(color.teal, 88) : na, title="Внутри окна по плану")
windowJustClosed = inWin[1] and not inWin
alertcondition(windowJustClosed,
title="Окно по плану закрыто",
message="Ваше торговое окно только что закрылось — управляйте лишь открытыми позициями, без новых входов (план, раздел 3).")
Результат: фон торговых часов и условие оповещения о закрытии окна («Окно по плану закрыто» — создайте оповещение после добавления индикатора). Оно обнаруживает первую свечу вне окна после свечи внутри, поэтому не гарантирует уведомления точно в момент закрытия: без новой свечи и обновления данных проверка не выполняется. Таймфрейм должен совмещать открытия и закрытия свечей с границами окна. Например, на M15 при окне 09:00–12:00 и доступной свече 12:00 подсветка заканчивается в 12:00, а условие активно на первой свече вне окна. «Once Per Bar» может уведомить на первом обновлении, «Once Per Bar Close» — только на закрытии. Пересекающиеся окна объединяются: конец первого не закрывает второе. Пересоздайте оповещение после изменения часов. Не ждите блокировки ордеров: индикатор напоминает план, а обеспечивает соблюдение чек-лист перед сделкой.
Шесть фрагментов с заголовками в одном текстовом файле, настройка и версии библиотек, затем тестовый CSV и ожидаемый вывод: для архива рядом с журналом или собственного репозитория. TXT объединяет разные языки — не запускайте целиком как Python. Выберите S1+S2+S3, отдельный S4 или один индикатор Pine.
Вопросы и ответы
Почему в русской версии сохранены английские технические имена?
Имена API, идентификаторы и технические поля сохраняют совместимость с pandas, Pine Script и исходными файлами; комментарии и сообщения этого набора переведены на русский. Пояснения вокруг фрагментов описывают, ЧТО делает код и когда он полезен; комментарии внутри — КАК. В исходном польском курсе принята библиотечная конвенция английских комментариев, согласованная с документацией и проверками кода в мастерской ИИ (приложение H, P3). Исключение польского промпта P5 — польские комментарии в специально созданном для вас одноразовом коде — относится к такому коду, а не к библиотеке.
Как запускать фрагменты Python?
11.8 пошагово объясняет установку Python, среды и пакетов; pandas и matplotlib достаточно для набора. Объедините S1–S3 в файл analiza_dziennika.py (S1 сверху) и запустите python analiza_dziennika.py в каталоге с экспортом журнала; S4 работает отдельно. Относительный CSV_PATH отсчитывается от рабочего каталога терминала. Начните с тестового CSV и анализируйте копию реального журнала; equity_curve.png перезаписывается при следующем запуске. Непонятную ошибку терминала вставьте вместе с кодом и полным сообщением в проверку P3 из приложения H вместо догадок.
Можно ли менять и расширять фрагменты?
Для этого и предназначен СТАРТОВЫЙ набор. Естественные расширения: показатели по сетапам (группировка по столбцу setup до вызова функции S2), фильтрация по error_code для матожидания чистого исполнения или отдельные кривые классов A+/B. Два правила изменений: проверка P3 для каждого (особенно request.security в Pine) и версии как определений показателей, так и правил стратегии. Ошибку расчёта исправляйте сразу и пересчитывайте сравниваемые периоды единым методом; изменение правил стратегии документируйте в протоколе тестирования (приложение N) и проверяйте на новых данных. Конец квартала сам по себе не оправдывает изменения, а незаконченный квартал — сохранения ошибки.
Почему в наборе нет стратегий и советников EA?
По той же причине, по которой мастерская ИИ не генерирует сигналы: готовая интернет-стратегия имеет неизвестные преимущество и допущения и не связана с вашим планом. EA, исполняющий чужую логику на вашем счёте, передаёт решения, за которые платите вы. Код курса усиливает процесс измерения, визуализации и соблюдения плана, а не заменяет его. Для автоматизации своей проверенной стратегии путь проходит через бэктест 15.4, протокол приложения N и проверку P3, а не копирование «прибыльных» скриптов.
math.floor в S4 вместо round: машина округляет вниз без споров, а человек вверх — с оправданием.Связанные материалы курса
- 11.8 Python в трейдинге — настройка среды, первый скрипт и пакеты
- Приложение F — таблица журнала — CSV для S1–S3 и те же показатели в формулах таблицы
- Приложение H, промпт P3 — проверка каждого изменения кода (lookahead, перерисовка, логические ошибки)
- Инструменты — калькуляторы — цена пипса и объём позиции в браузере для проверки S4
- Приложение E — шаблон плана — торговые окна и лимиты, отображаемые S6
- 15.10 Аудит стратегии — обоснованная интерпретация чисел набора
Источники
- Документация: pandas 3.0.5 и matplotlib 3.11.1 (функции S1–S3); Python: чтение CSV и арифметика Fraction (проверка формата и точный расчёт числа шагов лота); S1–S4 запускались на синтетических данных 17 сентября 2026 с Python 3.12.10; TradingView Pine Script v6: другие таймфреймы и данные, сессии, время и часовые пояса, оповещения (request.security с параметром lookahead и перерисовкой, hline, input.session, alertcondition); код S5–S6 проверен по документации без компиляции.
- Внутренние материалы: 11.8 Python в трейдинге (среда), 15.9 (определения показателей и формат журнала), 15.10 (принципы выводов) — набор является их сжатой практической реализацией.
- Van K. Tharp, Trade Your Way to Financial Freedom, 2-е изд., McGraw-Hill 2007 — результаты в R и матожидание, общий язык S2, таблицы F и промпта P5.