Kit de código do trader — Python e Pine Script
Seis trechos de código para copiar: quatro em Python (carregamento de diário CSV, métricas, curva de patrimônio com drawdown e dimensionador ATR) e dois em Pine Script (amplitude diária relativa ao ATR com alerta e janelas de sessão do plano no gráfico). Todos são ferramentas ANALÍTICAS — calculam, desenham gráficos e lembram regras; nenhum gera sinais de compra/venda ou toma decisões, pois essa é a função do playbook. Os comentários e as mensagens destinadas ao usuário estão em português; nomes de APIs, identificadores executáveis e elementos técnicos permanecem compatíveis com a documentação do pandas e do Pine Script. Essa localização das explicações humanas também se aplica à oficina de IA nos prompts que envolvem código; as explicações ao redor usam o idioma do curso e orientam você passo a passo. Ambiente: a instalação do Python e as primeiras execuções são abordadas em 11.8; os cabeçalhos das colunas do diário estão no suplemento F.
- Ferramentas, não estratégias: o código calcula métricas dos SEUS dados e acompanha o SEU plano — o limite é o mesmo da seção “o que a IA não faz” do suplemento H, pelas mesmas razões
- Um formato de dados compartilhado: os trechos Python leem os cabeçalhos da planilha do diário (suplemento F) — a taxa de acerto inclui operações no ponto de equilíbrio no denominador, e a expectativa usa o resultado líquido; são as mesmas definições do prompt P5
- Pine Script sem antecipação de dados: S5 busca os dados diários com
lookahead=barmerge.lookahead_off; S6 não acessa nenhum período gráfico superior (apenas a funçãotime). A ausência de antecipação não prova ausência de repainting — a descrição de S5 explica o que você vê nas barras históricas e em tempo real. São os problemas que uma revisão de código com o prompt P3 procura - O dimensionador arredonda o volume PARA BAIXO: ao converter risco em lotes, arredondar para cima aumenta sistematicamente o risco além do plano — essa linha de código faz a diferença entre 1% e “cerca de 1%”
Antes de executar o código: três regras
- Leia antes de executar. Cada trecho é deliberadamente curto — você deve entender cada linha. Modifique código que não compreende com a ajuda de uma revisão P3, não por adivinhação; essa regra vale em dobro para trechos de fóruns e chats.
- Os dados entram pelos arquivos; as decisões não saem do código. Os scripts leem uma exportação do diário (formato do suplemento F) e parâmetros que você fornece explicitamente. A saída são números e gráficos para a revisão semanal — você tira as conclusões, seguindo o processo de auditoria de 15.10 e considerando tamanho da amostra, dependências entre operações e incerteza do resultado.
- O ambiente de 11.8: Python 3.11 ou posterior com
pandasematplotlib(instalação e primeiro script são abordados ali); os trechos S1–S4 foram executados novamente em 17 de setembro de 2026 com Python 3.12.10, pandas 3.0.5 e matplotlib 3.11.1. Outras versões não foram testadas. Cole o Pine Script no editor de indicadores da plataforma de gráficos; ambos os indicadores usam a versão 6.
Etapas mínimas para executar o código: no ambiente Python 3.11+, confira a versão com python --version, depois instale os pacotes com python -m pip install pandas==3.0.5 matplotlib==3.11.1, salve S1+S2+S3 como analiza_dziennika.py e o CSV de teste como dziennik.csv, depois execute python analiza_dziennika.py. S4 exige apenas a biblioteca padrão. Cole S5 e S6 separadamente no Pine Editor. Os dois trechos Pine foram conferidos com a documentação v6; não foram compilados, e seus alertas não foram testados no TradingView.
S1 · Carregamento de diário CSV
Python 3 · pandasPonto de entrada de S2 e S3: lê a exportação da planilha do suplemento F, verifica os cabeçalhos e o número de campos e depois limpa a coluna r_net . Nomes de coluna duplicados, cabeçalho vazio e campos em excesso ou em falta interrompem a importação; o script não escolhe entre duas colunas de resultado nem transfere dados para o índice. Represente um campo vazio com um separador, por exemplo ;A+;;0; uma linha truncada é um caso diferente. Configure o separador e o caractere decimal da variante CSV (PL: ponto e vírgula e vírgula; EN: vírgula e ponto), junto com a codificação: arquivos do gerador do suplemento F usam UTF-8, e a variante “CSV UTF-8” salva no Excel também pode ser lida como UTF-8; uma exportação antiga com página de código polonesa pode exigir cp1250. Confira o formato de salvamento, porque o idioma da interface sozinho não determina a codificação. Um r_net vazio e um close_time_utc vazio significam que a operação ainda não foi fechada (e é ignorada); horário de fechamento sem resultado significa registro incompleto e interrompe os cálculos. Um valor não vazio que não pode ser lido como número (incluindo “NA” ou um traço) interrompe o script e informa o número do registro — assim como uma operação fechada sem horário de fechamento no formato do suplemento F (2026-07-08 13:15), pois, caso contrário, seria necessário adivinhar a sequência da curva.
import pandas as pd
CSV_PATH = "dziennik.csv" # exportação do diário (estrutura do anexo F)
CSV_SEP = ";" # ";" para CSV com configuração PL, "," para EN
DECIMAL = "," # "," para CSV com configuração PL, "." para EN
ENCODING = "utf-8-sig" # o gerador do anexo F grava UTF-8 (BOM tratado); CSV antigo com página de código polonesa pode exigir "cp1250"
REQUIRED = ["r_net", "setup", "setup_class", "error_code", "close_time_utc"]
# Ler arquivo local e validar sua estrutura ANTES de criar um DataFrame.
# pandas.read_csv pode renomear cabeçalhos duplicados ou inferir um índice de campos extras.
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("Não é possível ler o CSV: o cabeçalho está vazio.")
if any(not name or name != name.strip() for name in header):
raise SystemExit("Nome de coluna vazio ou com espaços nas extremidades — corrigir o cabeçalho CSV.")
duplicates = sorted({name for name in header if header.count(name) > 1})
if duplicates:
raise SystemExit(f"Colunas duplicadas: {duplicates} — resolver no diário.")
rows, record_indexes = [], []
for index, row in enumerate(reader):
if not row: # um registro CSV completamente vazio
continue
if len(row) != len(header):
raise SystemExit(f"Registro {index + 1}: esperados {len(header)} campos, recebidos {len(row)} "
f"— verificar separadores e aspas; nenhum campo foi descartado.")
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"Não é possível decodificar {CSV_PATH} como {ENCODING} — verificar UTF-8 ou a antiga cp1250.") from None
except (OSError, csv.Error) as exc:
raise SystemExit(f"Não é possível ler {CSV_PATH}: {exc}") from None
missing = [c for c in REQUIRED if c not in df.columns]
if missing:
raise SystemExit(f"Colunas ausentes: {missing} — conferir cabeçalhos com o anexo F e a configuração CSV_SEP.")
raw = df["r_net"] # resultado vazio permitido apenas se o horário de fechamento também estiver vazio
txt = raw.astype("string").str.strip().str.replace(DECIMAL, ".", regex=False) # interpretar a coluna diretamente: uma célula inválida não deve ocultar as legíveis
r = pd.to_numeric(txt, errors="coerce").astype("Float64") # evitar estouro de inteiros nas somas posteriores
r = r.where(r.abs() != float("inf")) # inf também não é um múltiplo R válido
invalid = raw.notna() & r.isna() # preenchido, mas ilegível como número
if invalid.any():
raise SystemExit(f"r_net inválido nos registros {(df.index[invalid] + 1).tolist()} "
f"(registro 1 = primeira linha abaixo do cabeçalho) — verificar valores e DECIMAL; "
f"NA, traços e infinito não são números.")
blank = df.isna().all(axis=1) # linha toda vazia = linha não utilizada da planilha (exportação XLSX integral), não uma operação
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 ausente para registros fechados {(df.index[incomplete] + 1).tolist()} "
f"— preencher o resultado líquido antes de calcular métricas.")
open_trades = int(r.isna().sum())
df = df.assign(r_net=r).dropna(subset=["r_net"]) # índice mantido = números de registro para a mensagem abaixo
# curva e drawdown exigem ordem cronológica (anexo F: por horário de fechamento); operação fechada sem horário legível interrompe o script
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) # o anexo F grava 2026-07-08 13:15; o formato fixo torna a verificação independente da ordem das linhas; utc=True evita falha por sufixo inesperado "Z"/"+00:00"
if closed.isna().any():
raise SystemExit(f"close_time_utc ilegível nos registros {(df.index[closed.isna()] + 1).tolist()} "
f"— toda operação fechada precisa de horário no formato do anexo F (2026-07-08 13:15); corrigir o diário, não o script.")
df = df.assign(_t=closed).sort_values("_t", kind="stable").drop(columns="_t").reset_index(drop=True)
print(f"Carregadas {len(df)} operações fechadas ({open_trades} linha(s) ignorada(s): sem horário de fechamento e sem r_net).")
Você obtém: um DataFrame, df, pronto para os próximos trechos, ordenado por horário de fechamento (curva e drawdown são calculados nessa ordem), mais a quantidade de operações abertas ignoradas (uma linha em branco significa registro inteiramente vazio, como na exportação de uma planilha XLSX inteira — o script não conta essas linhas; uma linha com dados, mas sem resultado ou horário de fechamento, é ignorada como ainda não fechada; um registro fechado sem resultado interrompe o script). Se ele parar com uma lista de registros, corrija as linhas indicadas no diário, não o script; se toda a coluna estiver afetada, confira também a constante DECIMAL . A numeração dos registros começa após o cabeçalho e inclui registros vazios; um campo entre aspas pode conter separador ou quebra de linha e continuar pertencendo ao mesmo registro. Cada operação deve aparecer uma vez: confira os identificadores trade_id antes de combinar exportações — S1 não elimina duplicações do histórico. Uma data sem horário é insuficiente para reconstruir a sequência. Um horário sem indicador de fuso é tratado como UTC; um deslocamento ISO 8601 explícito é convertido para UTC. Para horários idênticos, o script preserva a ordem dos registros — estabeleça essa ordem no diário, pois ela afeta o caminho do drawdown.
S2 · Métricas do diário
Python 3 · pandasAs mesmas definições do prompt P5 e do painel da planilha: a taxa de acerto inclui operações no ponto de equilíbrio no denominador; o fator de lucro retorna uma mensagem em vez de dividir por zero; a expectativa é a média de R líquido (r_net); e o drawdown é medido a partir da curva acumulada iniciada em 0 R (a primeira perda já é drawdown — como na fórmula da planilha F). Execute após S1. As definições das métricas são compartilhadas, mas a política de erros difere de P5: S1 interrompe a análise quando uma operação fechada tem resultado inválido, enquanto P5 instrui a ignorar essa linha e contá-la. Compare os resultados somente após estabelecer quais operações entraram nas duas amostras.
import math
def metrics(r):
"Métricas principais do diário sobre uma série de múltiplos R líquidos.\n Definições (iguais ao painel do anexo F):\n - taxa de acerto: operações com r > 0 sobre TODAS as válidas (break-even fica no denominador)\n - fator de lucro: soma dos r positivos dividida por abs(soma dos r negativos)\n - expectativa: média aritmética de r (líquida de custos)\n - drawdown máximo: maior queda da curva R acumulada desde seu máximo móvel,\n com início em 0 R (uma primeira perda de -1 R já é um drawdown de 1 R)"
n = len(r)
if n == 0:
raise SystemExit("Nenhuma operação válida — nada a medir.")
try:
r = r.astype(float)
except (TypeError, ValueError):
raise SystemExit("As métricas exigem valores R líquidos numéricos — executar S1 primeiro.") from None
if not r.map(math.isfinite).all():
raise SystemExit("As métricas exigem valores R líquidos finitos — executar S1 primeiro.")
wins = r[r > 0]
losses = r[r < 0]
equity = r.cumsum()
peak = equity.cummax().clip(lower=0) # anexo F: MAX(0; máximo móvel)
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("Intervalo numérico excedido — verificar os valores R; nenhuma métrica retornada.") 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("Intervalo numérico excedido — verificar os valores R; nenhuma métrica retornada.")
pf = "sem perdas na amostra" 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}")
Você obtém: seis métricas para a revisão semanal; se não houver perdas, PF é uma mensagem, não um número. Se os valores excederem o intervalo de cálculo, o script interrompe a análise em vez de retornar inf, NaN ou um drawdown aparentemente zero. WR = 0.4 significa 40%. PF é calculado em R, não em PLN; com risco monetário variável, esses resultados podem diferir. Os custos já estão incluídos em r_net — S2 não os desconta novamente. Não espere uma avaliação da vantagem apenas pela média ou simplesmente por ultrapassar 20 ou 50 operações. Você encontra as definições do painel no suplemento F, e o plano de seleção da amostra, custos e validação no suplemento N.
S3 · Curva de patrimônio e drawdown
Python 3 · pandas + matplotlibDesenha a curva acumulada em R com o drawdown em relação ao pico abaixo dela e salva um PNG ao lado do arquivo CSV indicado por CSV_PATH (S1), independentemente da pasta de onde você executa o script. A curva revela a sequência dos resultados e agrupamentos de perdas que desaparecem nos números agregados. É uma soma de R, não o saldo da conta em PLN ou patrimônio percentual: com risco monetário variável, não reproduzirá as mudanças do saldo. Este gráfico não inclui depósitos, saques nem resultados de posições abertas. Execute após S1.
import math
import matplotlib.pyplot as plt
from pathlib import Path
if len(df) == 0:
raise SystemExit("Nenhuma operação fechada — nada a desenhar.")
equity = df["r_net"].astype(float).cumsum()
drawdown = equity.cummax().clip(lower=0) - equity # mesma definição de S2 e anexo F (curva começa em 0 R)
if not equity.map(math.isfinite).all() or not drawdown.map(math.isfinite).all():
raise SystemExit("Intervalo numérico excedido — verificar os valores R; nenhum gráfico salvo.")
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 6), sharex=True,
gridspec_kw={"height_ratios": [3, 1]})
x = [0, *(equity.index + 1)] # operação 0 = ponto inicial de 0 R de onde se mede o drawdown
ax1.plot(x, [0.0, *equity.values])
ax1.set_ylabel("resultado (R)")
ax1.set_title("Curva de resultados — R líquidos acumulados")
ax1.grid(True, alpha=0.3)
ax2.fill_between(x, [0.0, *(-drawdown.values)], 0, alpha=0.5)
ax2.set_ylabel("drawdown (R)")
ax2.set_xlabel("operação n.º")
ax2.grid(True, alpha=0.3)
fig.tight_layout()
PNG_PATH = Path(CSV_PATH).with_name("equity_curve.png") # ao lado do arquivo do diário, independentemente do diretório de trabalho
fig.savefig(PNG_PATH, dpi=150)
plt.close(fig)
print(f"Salvo: {PNG_PATH}")
Você obtém: um arquivo equity_curve.png ao lado do diário; a curva começa em 0 R (operação 0), de onde o drawdown é medido. O painel inferior mostra o drawdown de R acumulado em relação ao pico (iniciando em 0 R, como em S2 e na planilha F) ao longo de todo o histórico — não é a perda semanal. Confira separadamente o limite semanal do plano (suplemento E), semana por semana, usando a unidade e a regra de reinício especificadas no plano.
Salve como dziennik.csv (UTF-8) ao lado do script combinado S1+S2+S3 e execute-o. O arquivo contém apenas as colunas necessárias para S1 — a exportação completa do suplemento F (26 colunas) é carregada da mesma forma. A última linha é uma operação aberta (r_net vazio); as duas primeiras operações fechadas são perdas, por isso o drawdown é medido a partir de 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;;
Saída esperada (Python 3.12.10, pandas 3.0.5, matplotlib 3.11.1; execução em 17 de setembro de 2026):
Carregadas 5 operações fechadas (1 linha(s) ignorada(s): sem horário de fechamento e sem 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
Salvo: equity_curve.png
Cálculo para conferir à mão: ganhos de 1.83 + 2.40 = 4.23 R, perdas de 1.00 + 1.08 = 2.08 R → PF 2.03; total 2.15 R / 5 = 0.43 R; curva −1.00 → −2.08 → −0.25 → −0.25 → 2.15, com pico inicial de 0 R → drawdown de 2.08 R (sem o ponto 0 R, seria 1.08 R — essa é a distinção por trás da definição no suplemento F). A saída se refere a esse arquivo exato e às versões informadas; se for diferente, confira os dados (separador, caractere decimal, codificação, ordem das linhas), as constantes em S1, o código e as versões dos pacotes, nessa ordem.
S4 · Dimensionador de posição por ATR
Python 3 · biblioteca padrãoVolume em lotes para uma distância de stop de k × ATR: o valor de risco vem do capital e da porcentagem, a distância vem do ATR, e o volume é arredondado PARA BAIXO ao passo de lote da sua conta (os parâmetros lot_step e min_lot , ambos com padrão de 0.01) — para que o risco PLANEJADO não exceda o orçamento. A perda real pode ser maior: este cálculo exclui slippage, gaps que atravessam o stop, spread, comissão e swap. Capital e valor do pip devem estar na mesma moeda da conta; confira separadamente o volume máximo e o requisito de margem nas especificações. Informe o ATR em pips (EURUSD 0.0080 → 80; USDJPY 0.80 → 80; o tamanho do pip é abordado no perfil do par, suplemento B); o valor do pip para 1 lote está nas especificações do instrumento (ou pode ser calculado pela calculadora do suplemento 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):
"Volume em lotes para um stop de atr_mult × ATR.\n atr_pips: ATR em PIPS, não em unidades de preço (EURUSD ATR 0.0080 -> 80; USDJPY ATR 0.80 -> 80 — tamanho do pip do par).\n pip_value_per_lot: valor de 1 pip para 1.00 lote, na moeda da conta\n (ex.: ~10 USD para EURUSD em conta USD — verificar especificações).\n lot_step / min_lot: passo e mínimo de volume da SUA conta (0.01 é comum, não universal).\n Arredonda PARA BAIXO a múltiplos de lot_step medidos desde zero. A aritmética de frações\n preserva entradas decimais sem depender da precisão global de Decimal.\n Risco planejado não é perda máxima: slippage, gaps, spread e swap não estão no modelo."
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("Usar valores numéricos, não texto ou booleanos (decimais Python usam ponto).")
decimals = tuple(Decimal(str(x)) for x in inputs)
if not all(x.is_finite() and x > 0 for x in decimals):
raise ValueError("Todas as entradas devem ser números finitos e positivos.")
c, p, a, k, v, step, minimum = map(Fraction, decimals)
if p > 100:
raise ValueError("risk_pct é uma porcentagem do capital (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": "Não há volume admissível para este lot_step e min_lot dentro do orçamento de risco."}
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("As entradas excedem o intervalo numérico da saída.") from None
if not all(math.isfinite(value) and value > 0 for value in result.values()):
raise ValueError("As entradas excedem o intervalo numérico da saída.")
return result # floats para exibição; sem arredondamento extra do stop ou dos valores monetários
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}
Você obtém: lotes arredondados para baixo ao passo e o valor de risco PLANEJADO resultante (no modelo sem custos, ≤ orçamento; a perda real pode ser maior). O passo é medido a partir de zero; confira se sua conta usa essa grade de volume. O stop e os valores monetários não recebem arredondamento adicional: por exemplo, ATR de 0.26 pips × 1.25 dá 0.325 pips, não 0.3. A saída é retornada como valores float para leitura, enquanto o número de passos de lote é calculado com frações exatas; o incremento mínimo de preço do instrumento ainda precisa ser conferido separadamente. Se ajustar o stop a esse incremento, recalcule o volume. Não espere uma decisão sobre entrar — o dimensionador calcula “quanto”, nunca “se”.
S5 · Amplitude diária versus ATR com alerta
Pine Script v6 · indicadorUma ferramenta de percepção da volatilidade (indicador intraday): nas barras em tempo real, mostra qual porcentagem do ATR diário o mercado já “consumiu” e avisa quando um limiar é cruzado — momento de consultar o plano, não de perseguir o preço. Os dados diários são obtidos sem antecipação (sem valores futuros); nas barras históricas, request.security mantém o último valor diário confirmado até o fim do período D seguinte, com o novo resultado desse período aparecendo na última barra intraday. Em tempo real, obtém a amplitude e o ATR em formação da vela D atual, portanto leituras anteriores podem mudar após recarregar (repainting). Um dia significa a vela D do provedor de dados, não um dia de calendário em Europe/Warsaw. O ATR no denominador também muda durante o dia; 100% não é um limite para o movimento do preço. Este método não consegue reconstruir nas barras históricas os sucessivos cruzamentos do limiar ocorridos hoje.
//@version=6
indicator("Faixa diária versus ATR (ferramenta de contexto)", overlay=false)
if not timeframe.isintraday
runtime.error("Usar gráfico intradiário temporal abaixo de 1D.")
atrLen = input.int(14, "Período ATR", minval=2)
warnPct = input.int(80, "Alertar quando a faixa diária atingir % do ATR", minval=10, maxval=200)
// Histórico: último valor D confirmado, atualizado no FINAL de cada período D.
// Tempo real: valores D em formação; leituras passadas podem mudar ao recarregar.
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, "Faixa diária como % do ATR", linewidth=2)
hline(100, "100% do ATR")
hline(warnPct, "Nível de alerta", linestyle=hline.style_dotted)
alertcondition(ta.crossover(rangePct, warnPct),
title="Faixa atingiu % do ATR",
message="A faixa diária atingiu sua % do ATR — reler o plano antes de qualquer nova entrada.")
Você obtém: um painel abaixo do gráfico e uma condição de alerta — crie o alerta na plataforma após adicionar o indicador, selecionando “Faixa atingiu % do ATR”. Use velas intraday padrão baseadas em tempo; dados Heikin Ashi/Renko podem ter características diferentes. Uma leitura ausente (na) significa que o ATR ou os dados necessários estão indisponíveis, não 0%. A condição exige passar de um valor ≤ limiar para um valor > limiar: apenas permanecer acima não aciona outro alerta. “Once Per Bar Close” restringe os alertas ao fechamento da vela intraday, mas não confirma toda a vela D. Recrie o alerta após mudar os parâmetros. Não espere um sinal direcional — uma leitura alta diz “o movimento já aconteceu”; o playbook diz o que fazer a respeito.
S6 · Janelas de sessão do plano de trading no gráfico
Pine Script v6 · indicadorA seção 3 do plano (suplemento E) desenhada no gráfico: destaca os horários em que você TEM PERMISSÃO para abrir posições e avisa quando a janela fecha. Informe os horários no fuso Europe/Warsaw — o identificador IANA considera CET/CEST. Por padrão, as janelas valem de segunda a sexta; uma opção as estende a todos os dias. O destaque confirma apenas o horário especificado no plano, não as demais condições de entrada. Use velas intraday padrão baseadas em tempo.
//@version=6
indicator("Janelas de sessão do plano de trading", overlay=true)
if not timeframe.isintraday
runtime.error("Usar gráfico intradiário temporal abaixo de 1D.")
tz = input.string("Europe/Warsaw", "Fuso horário das janelas")
win1 = input.session("0900-1200", "Janela 1")
win2 = input.session("1400-1700", "Janela 2")
weekdaysOnly = input.bool(true, "Apenas de segunda a sexta")
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="Dentro de uma janela do plano")
windowJustClosed = inWin[1] and not inWin
alertcondition(windowJustClosed,
title="Janela do plano fechada",
message="Sua janela de negociação acabou de fechar — gerenciar apenas posições abertas, sem novas entradas (plano, seção 3).")
Você obtém: sombreamento de fundo durante os horários de trading e uma condição de alerta para o fechamento da janela (“Janela do plano fechada” — crie o alerta na plataforma após adicionar o indicador). O alerta detecta a primeira vela fora da janela após uma vela dentro dela, portanto não garante uma notificação no horário exato do fechamento: sem nova vela e atualização de dados, não realiza verificação. Use um período gráfico cujas aberturas e fechamentos coincidam com os limites da janela. Por exemplo, em M15, com janela 09:00–12:00 e uma vela das 12:00 disponível, o sombreamento termina às 12:00 e a condição fica ativa nessa primeira vela fora da janela. “Once Per Bar” pode avisar na primeira atualização dela; “Once Per Bar Close”, só no fechamento. Janelas sobrepostas formam uma união: o fim da primeira não fecha a segunda. Recrie o alerta após mudar os horários. Não espere bloqueio de ordens — o indicador lembra o plano; a lista pré-operação o faz cumprir.
Seis trechos com títulos em um arquivo de texto, instruções de configuração e versões das bibliotecas, seguidos do CSV de teste e da saída esperada — para arquivar junto com o diário ou manter no próprio repositório. O TXT combina linguagens diferentes: não execute o arquivo inteiro como Python. Escolha S1+S2+S3, o S4 independente ou um único indicador Pine.
Perguntas frequentes
Por que os nomes técnicos permanecem em inglês e os comentários estão em português?
Nesta versão, comentários e mensagens destinados ao usuário foram traduzidos para português, enquanto nomes de APIs, identificadores, cabeçalhos CSV e elementos executáveis permanecem compatíveis com a documentação do pandas e do Pine Script. As explicações ao redor dos trechos dizem O QUE o código faz e quando usá-lo; os comentários internos explicam COMO. A oficina de IA (suplemento H, P3) mantém a mesma distinção ao revisar código; no prompt P5, os comentários do código gerado especificamente para você também usam o idioma local. Traduzir as explicações humanas não exige renomear uma API ou um cabeçalho de dados.
Como executo os trechos Python?
11.8 orienta você passo a passo na instalação do Python, do ambiente e dos pacotes — pandas e matplotlib são suficientes para este kit. Combine os trechos S1–S3 em um arquivo, analiza_dziennika.py (S1 no início), e execute python analiza_dziennika.py na pasta que contém a exportação do diário; S4 funciona de forma independente. O caminho relativo CSV_PATH se refere à pasta de trabalho do terminal. Comece pelo CSV de teste e analise uma cópia do seu diário real; equity_curve.png é sobrescrito na próxima execução. Se o terminal retornar um erro que você não entende, cole o código e a mensagem completa em uma revisão P3 do suplemento H, em vez de adivinhar.
Posso modificar e ampliar estes trechos?
É para isso que servem — este é um kit INICIAL. Extensões naturais incluem métricas por setup (agrupe pela coluna setup antes de chamar a função S2), filtragem por error_code para calcular a expectativa de execução sem erros ou curvas separadas para classes A+/B. Duas regras para modificações: submeta toda alteração a uma revisão P3 (especialmente o que envolver request.security no Pine) e versione tanto as definições das métricas quanto as regras da estratégia. Corrija imediatamente um erro de cálculo e recalcule os períodos comparados pelo mesmo método; documente uma mudança de regras da estratégia no protocolo de testes (suplemento N) e verifique-a com novos dados. O fim de um trimestre não justifica por si só uma mudança, e estar no meio dele não justifica manter um erro.
Por que o kit não contém estratégias ou EAs?
Pela mesma razão que a oficina de IA não gera sinais: uma estratégia pronta da internet tem vantagem e premissas desconhecidas e nenhuma ligação com seu plano — e um EA executando a lógica de outra pessoa na sua conta significa delegar decisões pelas quais só você paga. O código deste curso fortalece o processo (medição, visualização e cumprimento do plano), em vez de substituí-lo. Se quiser automatizar sua própria estratégia testada, o caminho passa pelo backtest de 15.4, pelo protocolo de testes do suplemento N e por uma revisão de código P3, não pela cópia de scripts “lucrativos”.
math.floor em S4 em vez de round: a máquina arredonda para baixo sem discutir; o humano arredonda para cima com uma justificativa.Material relacionado do curso
- 11.8 Python no trading — configuração do ambiente, primeiro script e trabalho com pacotes
- Suplemento F — planilha do diário — formato CSV lido por S1–S3 e as mesmas métricas expressas em fórmulas da planilha
- Suplemento H, prompt P3 — revisão de toda modificação neste código (antecipação de dados, repainting, erros de lógica)
- Seção de ferramentas — calculadoras — valor do pip e dimensionamento da posição no navegador para conferir os resultados de S4
- Suplemento E — modelo de plano — janelas e limites de trading que S6 desenha no gráfico
- 15.10 Auditoria da estratégia — interpretação disciplinada dos números produzidos pelo kit
Fontes
- Documentação: pandas 3.0.5 e matplotlib 3.11.1 (funções usadas em S1–S3); Python: leitura de CSV e aritmética com frações (validação de formato e cálculo exato do número de passos de lote) — os trechos S1–S4 foram executados com dados sintéticos em 17 de setembro de 2026 usando Python 3.12.10; TradingView Pine Script v6: outros períodos gráficos e dados, sessões, tempo e fusos horários, alertas (request.security com o parâmetro lookahead e repainting, hline, input.session, alertcondition) — o código S5–S6 foi revisado pela documentação, sem compilação.
- Interno: 11.8 Python no trading (ambiente), 15.9 (definições das métricas e formato do diário), 15.10 (princípios para tirar conclusões) — este kit é a implementação prática e condensada desses materiais.
- Van K. Tharp, Trade Your Way to Financial Freedom, 2ª ed., McGraw-Hill 2007 — múltiplos de R e expectativa matemática, a linguagem comum de S2, planilha F e prompt P5.