Paket kode trader — Python dan Pine Script
Enam cuplikan kode untuk disalin: empat dalam Python (memuat jurnal CSV, metrik, kurva ekuitas beserta drawdown, dan penghitung ukuran posisi ATR) serta dua dalam Pine Script (rentang harian terhadap ATR dengan peringatan, dan jendela sesi rencana trading pada grafik). Semuanya merupakan alat ANALISIS — menghitung, menggambar dan mengingatkan; tidak ada cuplikan yang menghasilkan sinyal beli/jual atau mengambil keputusan, karena itu tugas playbook. Pengenal kode dan nama API tetap dalam bahasa Inggris agar konsisten dengan dokumentasi pandas dan Pine Script; komentar dan label keluaran yang ditujukan kepada pembaca dilokalkan ke bahasa Indonesia. Konteks penggunaan kode dibahas pula dalam lokakarya AI untuk prompt yang melibatkan kode; penjelasan di sekitar cuplikan menggunakan bahasa kursus dan memandu Anda langkah demi langkah. Lingkungan: instalasi Python dan percobaan pertama dibahas dalam 11.8; judul kolom jurnal ada dalam lampiran F.
- Alat, bukan strategi: kode menghitung metrik dari data ANDA dan memantau rencana ANDA — batasannya sama dengan bagian “apa yang tidak dilakukan AI” dalam lampiran H, dengan alasan yang sama
- Format data bersama: cuplikan Python membaca judul kolom lembar jurnal (lampiran F) — tingkat kemenangan memasukkan transaksi impas dalam penyebut dan ekspektasi menggunakan hasil bersih; definisinya sama dengan prompt P5
- Pine Script tanpa lookahead: S5 mengambil data harian menggunakan
lookahead=barmerge.lookahead_off; S6 sama sekali tidak mengakses kerangka waktu yang lebih tinggi (hanya fungsitime). Ketiadaan lookahead tidak membuktikan ketiadaan repainting — uraian S5 menjelaskan tampilan pada bar historis dan secara waktu nyata. Inilah jebakan yang dicari dalam peninjauan kode dengan prompt P3 - Penghitung membulatkan volume KE BAWAH: saat mengubah risiko menjadi lot, pembulatan ke atas secara sistematis meningkatkan risiko melampaui rencana — satu baris kode itulah perbedaan antara 1% dan “sekitar 1%”
Sebelum menjalankan kode: tiga aturan
- Baca sebelum menjalankan. Setiap cuplikan sengaja dibuat singkat — Anda seharusnya memahami setiap baris. Ubah kode yang belum Anda pahami dengan bantuan peninjauan P3, bukan menebak; aturan ini berlaku lebih ketat lagi untuk cuplikan dari forum dan percakapan.
- Data masuk dari berkas; keputusan tidak keluar dari kode. Skrip membaca ekspor jurnal (format dari lampiran F) dan parameter yang Anda berikan secara eksplisit. Keluarannya berupa angka dan grafik untuk tinjauan mingguan — Anda yang menarik kesimpulan, mengikuti proses audit dalam 15.10 serta memperhitungkan ukuran sampel, ketergantungan antartransaksi dan ketidakpastian hasil.
- Lingkungan dari 11.8: Python 3.11 atau lebih baru dengan
pandasdanmatplotlib(instalasi dan skrip pertama dibahas di sana); cuplikan S1–S4 dijalankan ulang pada 17 September 2026 dengan Python 3.12.10, pandas 3.0.5 dan matplotlib 3.11.1. Versi lain belum diuji. Tempel Pine Script ke editor indikator platform grafik Anda; kedua indikator menggunakan versi 6.
Langkah minimum untuk menjalankan kode: pada lingkungan Python 3.11+ Anda, periksa versi dengan python --version, lalu instal paket dengan python -m pip install pandas==3.0.5 matplotlib==3.11.1, simpan S1+S2+S3 sebagai analiza_dziennika.py dan CSV uji sebagai dziennik.csv, lalu jalankan python analiza_dziennika.py. S4 hanya memerlukan pustaka standar. Tempel S5 dan S6 ke Pine Editor secara terpisah. Kedua cuplikan Pine diperiksa berdasarkan dokumentasi v6; keduanya belum dikompilasi dan peringatannya belum diuji di TradingView.
S1 · Memuat jurnal CSV
Python 3 · pandasTitik awal S2 dan S3: membaca ekspor lembar kerja dari lampiran F, memeriksa judul kolom dan jumlah kolom, lalu membersihkan kolom r_net . Nama kolom duplikat, judul kosong, serta kolom terlalu banyak atau terlalu sedikit menghentikan impor; skrip tidak memilih di antara dua kolom hasil atau memindahkan data ke indeks. Tunjukkan kolom kosong dengan pemisah, misalnya ;A+;;0; baris terpotong merupakan kasus berbeda. Atur pemisah dan karakter desimal untuk varian CSV (PL: titik koma dan koma; EN: koma dan titik), beserta pengodeannya: berkas dari generator lampiran F menggunakan UTF-8, dan varian “CSV UTF-8” yang disimpan di Excel juga dapat dibaca sebagai UTF-8; ekspor lama dengan halaman kode Polandia mungkin memerlukan cp1250. Periksa format penyimpanan, karena bahasa antarmuka saja tidak menentukan pengodean. Kolom r_net kosong dan kolom close_time_utc kosong berarti transaksi belum ditutup (dan dilewati); waktu penutupan tanpa hasil berarti catatan belum lengkap dan menghentikan perhitungan. Nilai terisi yang tidak dapat dibaca sebagai angka (termasuk “NA” atau tanda hubung) menghentikan skrip dan melaporkan nomor catatan — demikian pula transaksi ditutup tanpa waktu penutupan dalam format lampiran F (2026-07-08 13:15), karena jika tidak, urutan kurva harus ditebak.
import pandas as pd
CSV_PATH = "dziennik.csv" # ekspor jurnal (struktur lampiran F)
CSV_SEP = ";" # ";" untuk CSV dengan lokal PL, "," untuk EN
DECIMAL = "," # "," untuk CSV dengan lokal PL, "." untuk EN
ENCODING = "utf-8-sig" # generator lampiran F menulis UTF-8 (BOM ditangani); CSV lama dengan halaman kode Polandia mungkin memerlukan "cp1250"
REQUIRED = ["r_net", "setup", "setup_class", "error_code", "close_time_utc"]
# Baca berkas lokal dan validasi strukturnya SEBELUM membuat DataFrame.
# pandas.read_csv dapat mengganti nama judul kolom duplikat atau menyimpulkan indeks dari kolom tambahan.
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 tidak dapat dibaca: baris judul kosong.")
if any(not name or name != name.strip() for name in header):
raise SystemExit("Nama kolom kosong atau memiliki spasi di tepi — perbaiki judul kolom CSV.")
duplicates = sorted({name for name in header if header.count(name) > 1})
if duplicates:
raise SystemExit(f"Kolom duplikat: {duplicates} — perbaiki di jurnal.")
rows, record_indexes = [], []
for index, row in enumerate(reader):
if not row: # satu catatan CSV yang sepenuhnya kosong
continue
if len(row) != len(header):
raise SystemExit(f"Catatan {index + 1}: diharapkan {len(header)} kolom, ditemukan {len(row)} "
f"— periksa pemisah dan tanda kutip; tidak ada kolom yang dibuang.")
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"Tidak dapat mendekode {CSV_PATH} sebagai {ENCODING} — periksa UTF-8 atau cp1250 lama.") from None
except (OSError, csv.Error) as exc:
raise SystemExit(f"Tidak dapat membaca {CSV_PATH}: {exc}") from None
missing = [c for c in REQUIRED if c not in df.columns]
if missing:
raise SystemExit(f"Kolom yang belum ada: {missing} — periksa judul kolom terhadap lampiran F dan pengaturan CSV_SEP.")
raw = df["r_net"] # hasil kosong hanya diperbolehkan jika waktu penutupan juga kosong
txt = raw.astype("string").str.strip().str.replace(DECIMAL, ".", regex=False) # parsing kolom dilakukan sendiri: satu sel yang salah tidak boleh menyembunyikan sel yang dapat dibaca
r = pd.to_numeric(txt, errors="coerce").astype("Float64") # hindari luapan bilangan bulat dalam penjumlahan selanjutnya
r = r.where(r.abs() != float("inf")) # inf juga bukan kelipatan R yang valid
invalid = raw.notna() & r.isna() # terisi, tetapi tidak dapat dibaca sebagai angka
if invalid.any():
raise SystemExit(f"r_net tidak valid pada catatan {(df.index[invalid] + 1).tolist()} "
f"(catatan 1 = baris pertama di bawah judul) — periksa nilai dan DECIMAL; "
f"NA, tanda hubung dan tak hingga bukan angka.")
blank = df.isna().all(axis=1) # seluruh baris kosong = baris lembar yang tidak terpakai (ekspor seluruh lembar XLSX), bukan transaksi
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 belum ada untuk catatan yang ditutup {(df.index[incomplete] + 1).tolist()} "
f"— lengkapi hasil bersih sebelum menghitung metrik.")
open_trades = int(r.isna().sum())
df = df.assign(r_net=r).dropna(subset=["r_net"]) # indeks dipertahankan = nomor catatan untuk pesan di bawah
# kurva ekuitas dan drawdown memerlukan urutan kronologis (lampiran F: menurut waktu penutupan) — transaksi ditutup tanpa waktu penutupan yang terbaca menghentikan skrip
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) # lampiran F menulis 2026-07-08 13:15; format tetap menjaga pemeriksaan tidak bergantung pada urutan baris, utc=True mencegah akhiran "Z"/"+00:00" yang terselip membuatnya gagal
if closed.isna().any():
raise SystemExit(f"close_time_utc tidak terbaca pada catatan {(df.index[closed.isna()] + 1).tolist()} "
f"— setiap transaksi yang ditutup memerlukan waktu penutupan dalam format lampiran F (2026-07-08 13:15); perbaiki jurnal, bukan skrip.")
df = df.assign(_t=closed).sort_values("_t", kind="stable").drop(columns="_t").reset_index(drop=True)
print(f"Dimuat {len(df)} transaksi ditutup ({open_trades} baris dilewati: tanpa waktu penutupan dan tanpa r_net).")
Anda memperoleh: DataFrame, df, yang siap untuk cuplikan berikutnya, diurutkan menurut waktu penutupan (kurva dan drawdown dihitung dalam urutan itu), serta jumlah transaksi terbuka yang dilewati (baris kosong berarti catatan sepenuhnya kosong, seperti pada ekspor seluruh lembar XLSX — skrip tidak menghitung baris ini; baris berisi data tetapi tanpa hasil maupun waktu penutupan dilewati sebagai belum ditutup; entri ditutup tanpa hasil menghentikan skrip). Jika skrip berhenti dengan daftar catatan, perbaiki baris terkait dalam jurnal, bukan skrip; jika seluruh kolom terdampak, periksa juga konstanta DECIMAL . Penomoran catatan dimulai setelah judul dan mencakup catatan kosong; kolom dalam tanda kutip dapat memuat pemisah atau baris baru dan tetap menjadi bagian catatan yang sama. Setiap transaksi harus muncul sekali: periksa pengenal trade_id sebelum menggabungkan ekspor — S1 tidak menghapus duplikasi riwayat. Tanggal tanpa jam tidak cukup untuk merekonstruksi urutan. Waktu tanpa penanda zona waktu dianggap UTC; offset ISO 8601 eksplisit dikonversi ke UTC. Untuk waktu identik, skrip mempertahankan urutan catatan — tetapkan urutan itu di jurnal karena memengaruhi lintasan drawdown.
S2 · Metrik jurnal
Python 3 · pandasDefinisi sama dengan prompt P5 dan dasbor lembar kerja: tingkat kemenangan memasukkan transaksi impas dalam penyebut; profit factor mengembalikan pesan alih-alih membagi dengan nol; ekspektasi adalah rata-rata R bersih (r_net); dan drawdown diukur dari kurva kumulatif yang dimulai pada 0 R (kerugian pertama sudah merupakan drawdown — seperti rumus dalam lembar F). Jalankan setelah S1. Definisi metriknya sama, tetapi kebijakan kesalahan berbeda dari P5: S1 menghentikan analisis jika transaksi ditutup memiliki hasil tidak valid, sedangkan P5 memerintahkan untuk melewati baris itu dan menghitung jumlahnya. Bandingkan hasil hanya setelah menetapkan transaksi yang masuk ke kedua sampel.
import math
def metrics(r):
"Metrik inti jurnal pada deret kelipatan R bersih.\n Definisi (sama dengan dasbor lampiran F):\n - tingkat kemenangan: transaksi dengan r > 0 dibagi SEMUA transaksi valid (impas tetap dalam penyebut)\n - profit factor: jumlah r positif dibagi abs(jumlah r negatif)\n - ekspektasi: rata-rata aritmetika r (setelah biaya)\n - drawdown maksimum: penurunan terbesar kurva R kumulatif dari puncak berjalannya,\n kurva dimulai pada 0 R (jadi kerugian pertama -1 R sudah merupakan drawdown 1 R)\n"
n = len(r)
if n == 0:
raise SystemExit("Tidak ada transaksi valid — tidak ada yang dapat diukur.")
try:
r = r.astype(float)
except (TypeError, ValueError):
raise SystemExit("Metrik memerlukan nilai R bersih numerik — jalankan S1 terlebih dahulu.") from None
if not r.map(math.isfinite).all():
raise SystemExit("Metrik memerlukan nilai R bersih berhingga — jalankan S1 terlebih dahulu.")
wins = r[r > 0]
losses = r[r < 0]
equity = r.cumsum()
peak = equity.cummax().clip(lower=0) # lampiran F: MAX(0; puncak berjalan)
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("Rentang numerik terlampaui — periksa nilai R; tidak ada metrik yang dikembalikan.") 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("Rentang numerik terlampaui — periksa nilai R; tidak ada metrik yang dikembalikan.")
pf = "tidak ada kerugian dalam sampel" 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}")
Anda memperoleh: enam metrik untuk tinjauan mingguan; jika tidak ada kerugian, PF berupa pesan, bukan angka. Jika nilai melampaui rentang perhitungan, skrip menghentikan analisis alih-alih mengembalikan inf, NaN atau drawdown yang tampak nol. WR = 0.4 berarti 40%. PF dihitung dalam R, bukan PLN; jika risiko uang bervariasi, hasilnya dapat berbeda. Biaya sudah masuk ke dalam r_net — S2 tidak mengurangkannya lagi. Jangan mengharapkan penilaian keunggulan dari rata-rata saja atau sekadar setelah melewati 20 atau 50 transaksi. Definisi dasbor terdapat dalam lampiran F, sedangkan rencana pemilihan sampel, biaya dan validasi terdapat dalam lampiran N.
S3 · Kurva ekuitas dan drawdown
Python 3 · pandas + matplotlibMenggambar kurva R kumulatif dengan drawdown dari puncak di bawahnya dan menyimpan PNG di samping berkas CSV yang ditentukan oleh CSV_PATH (S1), terlepas dari direktori tempat skrip dijalankan. Kurva memperlihatkan urutan hasil dan kelompok kerugian yang tidak terlihat dalam angka agregat. Ini penjumlahan R, bukan saldo akun dalam PLN atau persentase ekuitas: jika risiko uang bervariasi, kurva tidak mereproduksi perubahan saldo. Grafik ini tidak mencakup setoran, penarikan atau hasil posisi terbuka. Jalankan setelah S1.
import math
import matplotlib.pyplot as plt
from pathlib import Path
if len(df) == 0:
raise SystemExit("Tidak ada transaksi ditutup — tidak ada yang dapat digambar.")
equity = df["r_net"].astype(float).cumsum()
drawdown = equity.cummax().clip(lower=0) - equity # definisi sama dengan S2 dan lampiran F (kurva dimulai pada 0 R)
if not equity.map(math.isfinite).all() or not drawdown.map(math.isfinite).all():
raise SystemExit("Rentang numerik terlampaui — periksa nilai R; grafik tidak disimpan.")
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 6), sharex=True,
gridspec_kw={"height_ratios": [3, 1]})
x = [0, *(equity.index + 1)] # transaksi 0 = titik awal 0 R yang menjadi acuan pengukuran drawdown
ax1.plot(x, [0.0, *equity.values])
ax1.set_ylabel("ekuitas (R)")
ax1.set_title("Kurva ekuitas — R bersih kumulatif")
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("transaksi #")
ax2.grid(True, alpha=0.3)
fig.tight_layout()
PNG_PATH = Path(CSV_PATH).with_name("equity_curve.png") # di samping berkas jurnal, terlepas dari direktori kerja
fig.savefig(PNG_PATH, dpi=150)
plt.close(fig)
print(f"Disimpan: {PNG_PATH}")
Anda memperoleh: berkas equity_curve.png di samping jurnal; kurva dimulai pada 0 R (transaksi 0), yang menjadi acuan pengukuran drawdown. Panel bawah menunjukkan drawdown R kumulatif dari puncaknya (dimulai pada 0 R, seperti S2 dan lembar F) sepanjang seluruh riwayat — ini bukan kerugian mingguan. Periksa batas mingguan dari rencana (lampiran E) secara terpisah, minggu demi minggu, menggunakan satuan dan aturan reset dalam rencana.
Simpan sebagai dziennik.csv (UTF-8) di samping skrip gabungan S1+S2+S3 lalu jalankan. Berkas hanya memuat kolom yang diperlukan S1 — ekspor lengkap dari lampiran F (26 kolom) dimuat dengan cara sama. Baris terakhir adalah transaksi terbuka (r_net kosong); dua transaksi ditutup pertama merugi, sehingga drawdown diukur dari 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;;
Keluaran yang diharapkan (Python 3.12.10, pandas 3.0.5, matplotlib 3.11.1; dijalankan pada 17 September 2026):
Dimuat 5 transaksi ditutup (1 baris dilewati: tanpa waktu penutupan dan tanpa 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
Disimpan: equity_curve.png
Perhitungan untuk diperiksa manual: keuntungan 1.83 + 2.40 = 4.23 R, kerugian 1.00 + 1.08 = 2.08 R → PF 2.03; total 2.15 R / 5 = 0.43 R; kurva −1.00 → −2.08 → −0.25 → −0.25 → 2.15, dengan puncak awal 0 R → drawdown 2.08 R (tanpa titik 0 R, hasilnya 1.08 R — inilah perbedaan di balik definisi lampiran F). Keluaran mengacu pada berkas persis ini dan versi yang dinyatakan; jika berbeda, periksa data (pemisah, karakter desimal, pengodean, urutan baris), konstanta S1, kode, lalu versi paket, sesuai urutan tersebut.
S4 · Penghitung ukuran posisi ATR
Python 3 · pustaka standarVolume dalam lot untuk jarak stop sebesar k × ATR: jumlah risiko berasal dari modal dan persentase, jarak dari ATR, dan volume dibulatkan KE BAWAH ke langkah lot akun Anda (parameter lot_step dan min_lot , keduanya bernilai awal 0.01) — agar risiko TERENCANA tidak melebihi anggaran. Kerugian aktual dapat lebih besar: perhitungan ini tidak mencakup slippage, gap melewati stop, spread, komisi dan swap. Modal dan nilai pip harus dalam mata uang akun yang sama; periksa secara terpisah volume maksimum dan persyaratan margin dalam spesifikasi. Masukkan ATR dalam pip (EURUSD 0.0080 → 80; USDJPY 0.80 → 80; ukuran pip dibahas dalam profil pasangan, lampiran B); nilai pip untuk 1 lot ada dalam spesifikasi instrumen (atau dapat dihitung menggunakan kalkulator lampiran 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 dalam lot untuk stop sebesar atr_mult × ATR.\n atr_pips: ATR dalam PIP, bukan satuan harga (EURUSD ATR 0.0080 -> 80; USDJPY ATR 0.80 -> 80 — ukuran pip pasangan).\n pip_value_per_lot: nilai 1 pip untuk 1.00 lot, dalam mata uang akun\n (mis. ~10 USD untuk EURUSD pada akun USD — periksa spesifikasi instrumen).\n lot_step / min_lot: langkah volume dan minimum akun ANDA (0.01 umum, tetapi tidak universal).\n Membulatkan KE BAWAH ke kelipatan lot_step, dihitung dari nol. Aritmetika Fraction\n mempertahankan masukan desimal tanpa bergantung pada presisi Decimal global.\n Risiko terencana bukan kerugian maksimum: slippage, gap, spread dan swap tidak tercakup dalam model ini.\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("Gunakan nilai numerik, bukan teks atau boolean (desimal Python menggunakan titik).")
decimals = tuple(Decimal(str(x)) for x in inputs)
if not all(x.is_finite() and x > 0 for x in decimals):
raise ValueError("Semua masukan harus berupa angka positif berhingga.")
c, p, a, k, v, step, minimum = map(Fraction, decimals)
if p > 100:
raise ValueError("risk_pct adalah persentase modal (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": "Tidak ada volume yang memenuhi lot_step dan min_lot ini dalam anggaran risiko."}
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("Masukan melebihi rentang numerik keluaran.") from None
if not all(math.isfinite(value) and value > 0 for value in result.values()):
raise ValueError("Masukan melebihi rentang numerik keluaran.")
return result # float untuk tampilan; tanpa pembulatan tambahan pada stop atau nilai uang
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}
Anda memperoleh: lot yang dibulatkan ke bawah sesuai langkah dan jumlah risiko TERENCANA yang dihasilkan (dalam model tanpa biaya, ≤ anggaran; kerugian aktual dapat lebih besar). Langkah diukur dari nol; periksa apakah akun menggunakan kisi volume ini. Stop dan jumlah uang tidak dibulatkan lagi: misalnya ATR 0.26 pip × 1.25 menghasilkan 0.325 pip, bukan 0.3. Keluaran dikembalikan sebagai nilai float untuk dibaca, sementara jumlah langkah lot dihitung menggunakan pecahan eksak; perubahan harga minimum instrumen tetap harus diperiksa secara terpisah. Jika Anda menyesuaikan stop ke perubahan minimum itu, hitung kembali volumenya. Jangan mengharapkan: keputusan untuk masuk posisi — penghitung menjawab “berapa banyak”, tidak pernah “apakah”.
S5 · Rentang harian vs ATR dengan peringatan
Pine Script v6 · indikatorAlat kesadaran volatilitas (indikator intrahari): pada bar waktu nyata, menampilkan persentase ATR harian yang sudah “terpakai” oleh pasar dan memberi peringatan saat ambang dilintasi — saat untuk membaca rencana, bukan mengejar harga. Data harian diambil tanpa lookahead (tanpa nilai masa depan); pada bar historis, request.security mempertahankan nilai harian terkonfirmasi terakhir sampai akhir periode D berikutnya, dengan hasil baru periode itu muncul pada bar intrahari terakhirnya. Secara waktu nyata, indikator mengambil rentang dan ATR candle D saat ini yang sedang berkembang, sehingga pembacaan sebelumnya dapat berubah setelah pemuatan ulang (repainting). Satu hari berarti candle D penyedia data, bukan hari kalender dalam Europe/Warsaw. ATR dalam penyebut juga berubah sepanjang hari; 100% bukan batas pergerakan harga. Metode ini tidak dapat merekonstruksi rangkaian lintasan ambang hari ini pada bar historis.
//@version=6
indicator("Rentang harian vs ATR (alat kesadaran)", overlay=false)
if not timeframe.isintraday
runtime.error("Gunakan grafik intrahari berbasis waktu di bawah 1D.")
atrLen = input.int(14, "Periode ATR", minval=2)
warnPct = input.int(80, "Peringatkan saat rentang harian mencapai % ATR", minval=10, maxval=200)
// Historis: nilai D terkonfirmasi terakhir, diperbarui pada AKHIR setiap periode D.
//Waktu nyata: nilai D yang sedang berkembang; pembacaan waktu nyata yang telah berlalu dapat berubah setelah pemuatan ulang.
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, "Rentang harian sebagai % ATR", linewidth=2)
hline(100, "100% ATR")
hline(warnPct, "Tingkat peringatan", linestyle=hline.style_dotted)
alertcondition(ta.crossover(rangePct, warnPct),
title="Rentang mencapai % ATR",
message="Rentang harian mencapai % ATR pilihan Anda — baca kembali rencana sebelum masuk posisi baru.")
Anda memperoleh: panel di bawah grafik dan kondisi peringatan — buat sendiri peringatannya di platform setelah menambahkan indikator, dengan memilih “Rentang mencapai % ATR”. Gunakan candle intrahari standar berbasis waktu; data Heikin Ashi/Renko dapat memiliki karakteristik berbeda. Pembacaan yang tidak tersedia (na) berarti ATR atau data yang diperlukan tidak tersedia, bukan 0%. Kondisi mensyaratkan pergerakan dari nilai ≤ ambang ke nilai > ambang: sekadar tetap berada di atasnya tidak memicu peringatan lain. “Once Per Bar Close” membatasi peringatan pada penutupan candle intrahari, tetapi tidak mengonfirmasi seluruh candle D. Buat ulang peringatan setelah mengubah parameter. Jangan mengharapkan: sinyal arah — pembacaan tinggi mengatakan “pergerakan sudah terjadi”; playbook memberi tahu tindakan Anda.
S6 · Jendela sesi rencana trading pada grafik
Pine Script v6 · indikatorBagian 3 rencana (lampiran E), digambar pada grafik: menyoroti jam ketika Anda BOLEH membuka posisi dan memberi peringatan saat jendela ditutup. Masukkan waktu dalam zona Europe/Warsaw — pengenal IANA memperhitungkan CET/CEST. Secara bawaan, jendela berlaku Senin hingga Jumat; ada pilihan untuk memperluasnya ke semua hari. Sorotan hanya mengonfirmasi waktu dalam rencana, bukan syarat masuk lainnya. Gunakan candle intrahari standar berbasis waktu.
//@version=6
indicator("Jendela sesi rencana trading", overlay=true)
if not timeframe.isintraday
runtime.error("Gunakan grafik intrahari berbasis waktu di bawah 1D.")
tz = input.string("Europe/Warsaw", "Zona waktu jendela")
win1 = input.session("0900-1200", "Jendela 1")
win2 = input.session("1400-1700", "Jendela 2")
weekdaysOnly = input.bool(true, "Hanya Senin sampai Jumat")
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="Di dalam jendela rencana")
windowJustClosed = inWin[1] and not inWin
alertcondition(windowJustClosed,
title="Jendela rencana ditutup",
message="Jendela trading Anda baru saja ditutup — kelola hanya posisi terbuka, tanpa entri baru (rencana, bagian 3).")
Anda memperoleh: arsiran latar selama jam trading dan kondisi peringatan saat jendela ditutup (“Jendela rencana ditutup” — buat peringatan di platform setelah menambahkan indikator). Peringatan mendeteksi candle pertama di luar jendela setelah candle di dalamnya, sehingga tidak menjamin pemberitahuan tepat pada waktu penutupan: tanpa candle baru dan pembaruan data, tidak ada pemeriksaan. Gunakan kerangka waktu yang pembukaan dan penutupannya sejajar dengan batas jendela. Misalnya pada M15, dengan jendela 09:00–12:00 dan candle 12:00 tersedia, arsiran berakhir pada 12:00 dan kondisi aktif pada candle pertama di luar jendela itu. “Once Per Bar” dapat memberi tahu pada pembaruan pertamanya; “Once Per Bar Close” hanya saat penutupannya. Jendela yang bertumpang tindih membentuk gabungan: berakhirnya jendela pertama tidak menutup yang kedua. Buat ulang peringatan setelah mengubah waktu. Jangan mengharapkan: pemblokiran order — indikator mengingatkan rencana; daftar periksa pratransaksi Anda yang menegakkannya.
Enam cuplikan beserta judul dalam satu berkas teks, petunjuk penyiapan dan versi pustaka, diikuti CSV uji serta keluaran yang diharapkan — untuk diarsipkan bersama jurnal atau disimpan dalam repositori Anda. TXT menggabungkan bahasa berbeda: jangan jalankan seluruh berkas sebagai Python. Pilih S1+S2+S3, S4 mandiri, atau satu indikator Pine.
Tanya jawab
Mengapa pengenal kode tetap berbahasa Inggris, sedangkan komentar dari sumber kursus Polandia dilokalkan?
Pada sumber kursus Polandia, komentar berbahasa Inggris mengikuti nama API, dokumentasi pandas dan Pine Script serta pesan kesalahan; lokakarya AI menggunakan pendekatan itu untuk prompt yang melibatkan kode (lampiran H, P3). Dalam paket versi Indonesia ini, pengenal dan API tetap berbahasa Inggris, sedangkan komentar serta label keluaran untuk pembaca diterjemahkan. Penjelasan di sekitar cuplikan menerangkan APA yang dilakukan kode dan kapan digunakan; komentar di dalamnya menjelaskan BAGAIMANA. Pengecualian dalam versi Polandia prompt P5 (komentar Polandia pada kode yang dibuat khusus untuk Anda) berkaitan dengan kode sekali pakai, bukan aturan asli pustaka.
Bagaimana menjalankan cuplikan Python?
11.8 memandu Anda langkah demi langkah untuk menginstal Python, lingkungan dan paket — pandas dan matplotlib sudah cukup untuk paket ini. Gabungkan cuplikan S1–S3 dalam satu berkas, analiza_dziennika.py (S1 di paling atas), lalu jalankan python analiza_dziennika.py di direktori berisi ekspor jurnal; S4 berjalan mandiri. Jalur relatif CSV_PATH mengacu pada direktori kerja terminal. Mulai dengan CSV uji dan analisis salinan jurnal sungguhan Anda; equity_curve.png ditimpa pada proses berikutnya. Jika terminal menampilkan kesalahan yang belum Anda pahami, tempel kode dan pesan lengkapnya ke peninjauan P3 dari lampiran H, alih-alih menebak.
Bolehkah saya mengubah dan memperluas cuplikan ini?
Memang itulah tujuannya — ini paket AWAL. Perluasan yang wajar antara lain metrik per setup (kelompokkan menurut kolom setup sebelum memanggil fungsi S2), penyaringan menurut error_code untuk menghitung ekspektasi pelaksanaan tanpa kesalahan, atau kurva terpisah untuk kelas A+/B. Dua aturan perubahan: tinjau setiap perubahan melalui P3 (terutama yang melibatkan request.security dalam Pine), serta beri versi pada definisi metrik dan aturan strategi. Perbaiki kesalahan perhitungan segera dan hitung ulang periode pembanding dengan metode sama; dokumentasikan perubahan aturan strategi dalam protokol pengujian (lampiran N) dan periksa menggunakan data baru. Berakhirnya triwulan sendiri tidak membenarkan perubahan, dan berada di tengah triwulan tidak membenarkan mempertahankan kesalahan.
Mengapa paket tidak memuat strategi atau EA?
Dengan alasan sama mengapa lokakarya AI tidak menghasilkan sinyal: strategi siap pakai dari internet memiliki keunggulan tidak diketahui, asumsi tidak diketahui dan tidak terkait rencana Anda — sedangkan EA yang menjalankan logika orang lain pada akun Anda berarti mendelegasikan keputusan yang seluruh biayanya Anda tanggung. Kode dalam kursus memperkuat proses (pengukuran, visualisasi dan kepatuhan pada rencana), bukan menggantikannya. Jika ingin mengotomatiskan strategi Anda sendiri yang telah diuji, jalurnya melalui backtest dalam 15.4, protokol pengujian lampiran N, dan peninjauan kode P3, bukan menyalin skrip “menguntungkan”.
math.floor dalam S4, bukan round: mesin membulatkan ke bawah tanpa berdebat; manusia membulatkan ke atas dengan pembenaran.Materi kursus terkait
- 11.8 Python dalam trading — menyiapkan lingkungan, skrip pertama dan bekerja dengan paket
- Lampiran F — lembar jurnal — format CSV yang dibaca S1–S3 dan metrik sama dalam bentuk rumus lembar kerja
- Lampiran H, prompt P3 — meninjau setiap perubahan kode ini (lookahead, repainting, kesalahan logika)
- Bagian alat — kalkulator — nilai pip dan ukuran posisi berbasis peramban untuk memeriksa hasil S4
- Lampiran E — templat rencana — jendela trading dan batas yang digambar S6 pada grafik
- 15.10 Audit strategi — penafsiran disiplin atas angka yang dihasilkan paket ini
Sumber
- Dokumentasi: pandas 3.0.5 dan matplotlib 3.11.1 (fungsi dalam S1–S3); Python: pembacaan CSV dan aritmetika Fraction (validasi format dan perhitungan eksak jumlah langkah lot) — cuplikan S1–S4 dijalankan pada data sintetis tanggal 17 September 2026 menggunakan Python 3.12.10; TradingView Pine Script v6: kerangka waktu dan data lain, sesi, waktu dan zona waktu, peringatan (request.security dengan parameter lookahead dan repainting, hline, input.session, alertcondition) — kode S5–S6 ditinjau berdasarkan dokumentasi, tanpa kompilasi.
- Internal: 11.8 Python dalam trading (lingkungan), 15.9 (definisi metrik dan format jurnal), 15.10 (prinsip penarikan kesimpulan) — paket ini merupakan penerapan praktis ringkas dari materi tersebut.
- Van K. Tharp, Trade Your Way to Financial Freedom, edisi ke-2, McGraw-Hill 2007 — kelipatan R dan ekspektasi, bahasa bersama S2, lembar F dan prompt P5.