Bộ mã cho trader — Python và Pine Script
Sáu đoạn mã để sao chép: bốn đoạn Python (đọc nhật ký CSV, chỉ số, đường vốn kèm drawdown và tính khối lượng theo ATR) cùng hai đoạn Pine Script (biên độ ngày so với ATR có cảnh báo và khung giờ theo kế hoạch trên biểu đồ). Tất cả đều là công cụ PHÂN TÍCH — tính toán, vẽ và nhắc nhở; không đoạn nào tạo tín hiệu mua/bán hay đưa ra quyết định, vì đó là việc của playbook. Tên định danh và API giữ tiếng Anh để nhất quán với tên API, tài liệu pandas và Pine Script cùng thông báo lỗi hệ thống; chú thích và nhãn kết quả dành cho người đọc được dịch sang tiếng Việt. Cách phân biệt phần kỹ thuật và phần diễn giải này cũng được áp dụng trong xưởng thực hành AI cho các prompt liên quan đến mã; phần giải thích xung quanh dùng ngôn ngữ khóa học và hướng dẫn từng bước. Môi trường: cách cài Python và chạy lần đầu được trình bày trong 11.8; tiêu đề cột nhật ký nằm trong phụ lục F.
- Công cụ, không phải chiến lược: mã tính chỉ số từ dữ liệu CỦA BẠN và theo dõi kế hoạch CỦA BẠN — ranh giới giống phần “AI không làm gì” của phụ lục H, với cùng lý do
- Định dạng dữ liệu chung: các đoạn Python đọc tiêu đề từ bảng nhật ký (phụ lục F) — tỷ lệ thắng tính cả giao dịch hòa vốn trong mẫu số, kỳ vọng dùng kết quả ròng; đây cũng là định nghĩa trong prompt P5
- Pine Script không nhìn trước: S5 lấy dữ liệu ngày bằng
lookahead=barmerge.lookahead_off; S6 hoàn toàn không truy cập khung thời gian cao hơn (chỉ dùng hàmtime). Không nhìn trước không có nghĩa là không repaint — mô tả S5 giải thích những gì xuất hiện trên nến lịch sử và thời gian thực. Đây là những lỗi mà rà soát mã bằng prompt P3 tìm kiếm - Công cụ khối lượng làm tròn XUỐNG: khi đổi rủi ro thành lot, làm tròn lên làm rủi ro vượt kế hoạch một cách có hệ thống — một dòng mã đó là khác biệt giữa 1% và “khoảng 1%”
Trước khi chạy mã: ba quy tắc
- Đọc trước khi chạy. Mỗi đoạn được cố ý giữ ngắn — bạn cần hiểu từng dòng. Sửa mã chưa hiểu với sự hỗ trợ của rà soát P3, không đoán mò; quy tắc càng quan trọng với mã lấy từ diễn đàn và chat.
- Dữ liệu đi vào từ tệp; quyết định không đi ra từ mã. Script đọc bản xuất nhật ký (định dạng phụ lục F) và tham số bạn cung cấp rõ ràng. Đầu ra là số liệu và biểu đồ cho buổi rà soát tuần — bạn tự kết luận theo quy trình kiểm toán ở 15.10, có tính đến kích thước mẫu, phụ thuộc giữa giao dịch và bất định của kết quả.
- Môi trường trong 11.8: Python 3.11 trở lên với
pandasvàmatplotlib(cách cài và script đầu tiên được hướng dẫn ở đó); các đoạn S1–S4 được chạy lại ngày 17 tháng Chín năm 2026 bằng Python 3.12.10, pandas 3.0.5 và matplotlib 3.11.1. Chưa kiểm thử phiên bản khác. Dán Pine Script vào trình soạn chỉ báo của nền tảng biểu đồ; cả hai chỉ báo dùng phiên bản 6.
Các bước tối thiểu: trong môi trường Python 3.11+, kiểm tra phiên bản bằng python --version, rồi cài gói bằng python -m pip install pandas==3.0.5 matplotlib==3.11.1, lưu S1+S2+S3 thành analiza_dziennika.py và CSV thử thành dziennik.csv, rồi chạy python analiza_dziennika.py. S4 chỉ cần thư viện chuẩn. Dán riêng S5 và S6 vào Pine Editor. Hai đoạn Pine đã được đối chiếu tài liệu v6; chưa được biên dịch và chưa kiểm thử cảnh báo trong TradingView.
S1 · Đọc nhật ký CSV
Python 3 · pandasĐiểm bắt đầu cho S2 và S3: đọc bản xuất bảng tính từ phụ lục F, kiểm tra tiêu đề và số trường, rồi làm sạch cột r_net . Tên cột trùng, tiêu đề trống, quá nhiều hoặc quá ít trường sẽ dừng nhập; script không tự chọn giữa hai cột kết quả hoặc chuyển dữ liệu sang chỉ mục. Thể hiện ô trống bằng dấu phân cách, ví dụ ;A+;;0; hàng bị cắt cụt là trường hợp khác. Đặt dấu phân cách và dấu thập phân theo biến thể CSV (PL: chấm phẩy và dấu phẩy; EN: dấu phẩy và dấu chấm), cùng mã hóa: tệp từ bộ tạo phụ lục F dùng UTF-8, còn bản “CSV UTF-8” lưu trong Excel cũng có thể đọc bằng UTF-8; bản xuất cũ dùng bảng mã tiếng Ba Lan có thể cần cp1250. Kiểm tra định dạng lưu, vì riêng ngôn ngữ giao diện không xác định mã hóa. Nếu r_net trống và close_time_utc trống thì giao dịch chưa đóng (và bị bỏ qua); có thời gian đóng nhưng không có kết quả nghĩa là bản ghi thiếu, phép tính sẽ dừng. Giá trị không trống nhưng không đọc được thành số (kể cả “NA” hoặc dấu gạch) sẽ dừng script và báo số bản ghi — tương tự giao dịch đã đóng nhưng thiếu thời gian đóng trong định dạng phụ lục F (2026-07-08 13:15), vì nếu không sẽ phải đoán thứ tự đường vốn.
import pandas as pd
CSV_PATH = "dziennik.csv" # tệp xuất nhật ký (cấu trúc phần bổ sung F)
CSV_SEP = ";" # ";" cho CSV vùng PL, "," cho EN
DECIMAL = "," # "," cho CSV vùng PL, "." cho EN
ENCODING = "utf-8-sig" # bộ tạo phần bổ sung F ghi UTF-8 (xử lý BOM); CSV mã Ba Lan cũ có thể cần "cp1250"
REQUIRED = ["r_net", "setup", "setup_class", "error_code", "close_time_utc"]
# Đọc tệp cục bộ và kiểm tra cấu trúc TRƯỚC khi tạo DataFrame.
# pandas.read_csv có thể đổi tên tiêu đề trùng hoặc suy chỉ mục từ trường dư.
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("Không đọc được CSV: tiêu đề trống.")
if any(not name or name != name.strip() for name in header):
raise SystemExit("Tên cột trống hoặc có khoảng trắng bao quanh — sửa tiêu đề CSV.")
duplicates = sorted({name for name in header if header.count(name) > 1})
if duplicates:
raise SystemExit(f"Cột trùng: {duplicates} — xử lý trong nhật ký.")
rows, record_indexes = [], []
for index, row in enumerate(reader):
if not row: # một bản ghi CSV hoàn toàn trống
continue
if len(row) != len(header):
raise SystemExit(f"Bản ghi {index + 1}: cần {len(header)} trường, nhận {len(row)} "
f"— kiểm tra dấu phân cách và ngoặc kép; chưa bỏ trường nào.")
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"Không giải mã được {CSV_PATH} theo {ENCODING} — kiểm tra UTF-8 hoặc cp1250 cũ.") from None
except (OSError, csv.Error) as exc:
raise SystemExit(f"Không đọc được {CSV_PATH}: {exc}") from None
missing = [c for c in REQUIRED if c not in df.columns]
if missing:
raise SystemExit(f"Thiếu cột: {missing} — đối chiếu tiêu đề với phần bổ sung F và thiết lập CSV_SEP.")
raw = df["r_net"] # chỉ cho phép kết quả trống khi giờ đóng cũng trống
txt = raw.astype("string").str.strip().str.replace(DECIMAL, ".", regex=False) # tự đọc cột: một ô lỗi không được che những ô đọc được
r = pd.to_numeric(txt, errors="coerce").astype("Float64") # tránh tràn số nguyên quay vòng trong các tổng sau
r = r.where(r.abs() != float("inf")) # inf cũng không phải bội số R hợp lệ
invalid = raw.notna() & r.isna() # đã điền nhưng không đọc được như số
if invalid.any():
raise SystemExit(f"r_net sai trong bản ghi {(df.index[invalid] + 1).tolist()} "
f"(bản ghi 1 = dòng đầu dưới tiêu đề) — kiểm tra giá trị và DECIMAL; "
f"NA, gạch ngang và vô hạn không phải số.")
blank = df.isna().all(axis=1) # cả dòng trống = dòng bảng chưa dùng (xuất toàn sheet XLSX), không phải giao dịch
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"Thiếu r_net ở bản ghi đã đóng {(df.index[incomplete] + 1).tolist()} "
f"— điền kết quả ròng trước tính chỉ số.")
open_trades = int(r.isna().sum())
df = df.assign(r_net=r).dropna(subset=["r_net"]) # giữ chỉ mục = số bản ghi cho thông báo dưới
# đường equity và drawdown cần thứ tự thời gian (phần bổ sung F: theo giờ đóng) — giao dịch đóng không có giờ đóng đọc được sẽ dừng 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) # phần bổ sung F ghi 2026-07-08 13:15; định dạng cố định làm kiểm tra độc lập thứ tự dòng, utc=True tránh hậu tố "Z"/"+00:00" lạc gây lỗi
if closed.isna().any():
raise SystemExit(f"close_time_utc không đọc được ở bản ghi {(df.index[closed.isna()] + 1).tolist()} "
f"— mọi giao dịch đóng cần giờ đóng đúng định dạng phần bổ sung F (2026-07-08 13:15); sửa nhật ký, không sửa script.")
df = df.assign(_t=closed).sort_values("_t", kind="stable").drop(columns="_t").reset_index(drop=True)
print(f"Đã nạp {len(df)} giao dịch đóng ({open_trades} dòng bỏ qua: không giờ đóng và không r_net).")
Bạn nhận được: một DataFrame, df, sẵn sàng cho các đoạn tiếp theo, sắp theo thời gian đóng (đường vốn và drawdown tính theo thứ tự đó), cùng số giao dịch mở bị bỏ qua (hàng trống là bản ghi hoàn toàn trống, như khi xuất toàn bộ trang XLSX — script không đếm những hàng này; hàng có dữ liệu nhưng thiếu kết quả và thời gian đóng được bỏ qua như chưa đóng; giao dịch đã đóng nhưng thiếu kết quả sẽ dừng script). Nếu script dừng với danh sách bản ghi, sửa các hàng được chỉ ra trong nhật ký, không sửa script; nếu cả cột bị ảnh hưởng, kiểm tra thêm hằng số DECIMAL . Số bản ghi bắt đầu sau tiêu đề và bao gồm bản ghi trống; trường đặt trong dấu nháy có thể chứa dấu phân cách hoặc xuống dòng mà vẫn thuộc cùng bản ghi. Mỗi giao dịch chỉ nên xuất hiện một lần: kiểm tra mã trade_id trước khi gộp các bản xuất — S1 không loại lịch sử trùng. Ngày không có giờ không đủ để dựng lại trình tự. Giờ không có ký hiệu múi giờ được coi là UTC; độ lệch ISO 8601 rõ ràng được đổi sang UTC. Với thời gian giống nhau, script giữ thứ tự bản ghi — hãy xác định thứ tự trong nhật ký vì nó ảnh hưởng diễn biến drawdown.
S2 · Chỉ số nhật ký
Python 3 · pandasCùng định nghĩa với prompt P5 và bảng tổng hợp trong bảng tính: tỷ lệ thắng tính cả giao dịch hòa vốn trong mẫu số; profit factor trả thông báo thay vì chia cho không; kỳ vọng là trung bình R ròng (r_net); drawdown được đo từ đường lũy kế bắt đầu tại 0 R (khoản lỗ đầu tiên đã là drawdown — như công thức trong bảng F). Chạy sau S1. Định nghĩa chỉ số giống nhau nhưng chính sách lỗi khác P5: S1 dừng phân tích khi giao dịch đã đóng có kết quả không hợp lệ, còn P5 yêu cầu bỏ hàng đó và đếm. Chỉ so sánh sau khi xác định những giao dịch được đưa vào cả hai mẫu.
import math
def metrics(r):
"Chỉ số nhật ký cốt lõi trên chuỗi bội số R ròng.\n Định nghĩa (như bảng thống kê phần bổ sung F):\n - tỷ lệ thắng: giao dịch r > 0 trên MỌI giao dịch hợp lệ (hòa vốn vẫn trong mẫu số)\n - profit factor: tổng r dương trên abs(tổng r âm)\n - kỳ vọng: trung bình cộng r (đã trừ chi phí)\n - drawdown tối đa: mức giảm lớn nhất của đường R tích lũy từ đỉnh lũy kế,\n đường bắt đầu ở 0 R (nên lỗ đầu -1 R đã là drawdown 1 R)"
n = len(r)
if n == 0:
raise SystemExit("Không giao dịch hợp lệ — không có gì để đo.")
try:
r = r.astype(float)
except (TypeError, ValueError):
raise SystemExit("Chỉ số cần R ròng dạng số — chạy S1 trước.") from None
if not r.map(math.isfinite).all():
raise SystemExit("Chỉ số cần R ròng hữu hạn — chạy S1 trước.")
wins = r[r > 0]
losses = r[r < 0]
equity = r.cumsum()
peak = equity.cummax().clip(lower=0) # phần bổ sung F: MAX(0; đỉnh lũy kế)
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("Vượt miền số — kiểm tra R; không trả chỉ số.") 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("Vượt miền số — kiểm tra R; không trả chỉ số.")
pf = "không có lệnh lỗ trong mẫu" 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}")
Bạn nhận được: sáu chỉ số cho rà soát tuần; nếu không có lỗ, PF là thông báo thay vì con số. Nếu giá trị vượt phạm vi tính toán, script dừng phân tích thay vì trả về inf, NaN hoặc drawdown có vẻ bằng không. WR = 0.4 nghĩa là 40%. PF tính theo R, không phải PLN; khi rủi ro tiền thay đổi, các kết quả có thể khác nhau. Chi phí đã được tính trong r_net — S2 không trừ lại. Đừng kỳ vọng chỉ số trung bình, hay đơn giản vượt 20 hoặc 50 giao dịch, sẽ đánh giá được lợi thế. Định nghĩa bảng tổng hợp có trong phụ lục F, còn kế hoạch chọn mẫu, chi phí và xác thực nằm trong phụ lục N.
S3 · Đường vốn và drawdown
Python 3 · pandas + matplotlibVẽ đường R lũy kế với drawdown từ đỉnh ở bên dưới, lưu PNG cạnh tệp CSV được chỉ định bởi CSV_PATH (S1), bất kể thư mục chạy script. Đường vốn thể hiện thứ tự kết quả và cụm thua lỗ bị che trong số liệu tổng hợp. Đây là tổng R, không phải số dư tài khoản theo PLN hay phần trăm vốn chủ sở hữu: khi rủi ro tiền thay đổi, nó không tái hiện biến động số dư. Biểu đồ không gồm nạp, rút hoặc kết quả vị thế mở. Chạy sau S1.
import math
import matplotlib.pyplot as plt
from pathlib import Path
if len(df) == 0:
raise SystemExit("Không giao dịch đóng — không có gì để vẽ.")
equity = df["r_net"].astype(float).cumsum()
drawdown = equity.cummax().clip(lower=0) - equity # cùng định nghĩa S2 và phần bổ sung F (đường bắt đầu ở 0 R)
if not equity.map(math.isfinite).all() or not drawdown.map(math.isfinite).all():
raise SystemExit("Vượt miền số — kiểm tra R; không lưu biểu đồ.")
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 6), sharex=True,
gridspec_kw={"height_ratios": [3, 1]})
x = [0, *(equity.index + 1)] # giao dịch 0 = điểm bắt đầu 0 R dùng đo drawdown
ax1.plot(x, [0.0, *equity.values])
ax1.set_ylabel("equity (R)")
ax1.set_title("Đường equity — R ròng tích lũy")
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("giao dịch #")
ax2.grid(True, alpha=0.3)
fig.tight_layout()
PNG_PATH = Path(CSV_PATH).with_name("equity_curve.png") # cạnh tệp nhật ký, bất kể thư mục làm việc
fig.savefig(PNG_PATH, dpi=150)
plt.close(fig)
print(f"Đã lưu: {PNG_PATH}")
Bạn nhận được: tệp equity_curve.png cạnh nhật ký; đường bắt đầu tại 0 R (giao dịch 0), từ đó đo drawdown. Khung dưới hiển thị drawdown của R lũy kế so với đỉnh (bắt đầu tại 0 R như S2 và bảng F) trên toàn bộ lịch sử — không phải lỗ tuần. Kiểm tra riêng giới hạn tuần trong kế hoạch (phụ lục E), từng tuần, theo đơn vị và quy tắc đặt lại đã ghi.
Lưu thành dziennik.csv (UTF-8) cạnh script ghép S1+S2+S3 rồi chạy. Tệp chỉ chứa các cột S1 cần — bản xuất đầy đủ từ phụ lục F (26 cột) cũng được đọc tương tự. Hàng cuối là giao dịch mở (r_net trống); hai giao dịch đã đóng đầu tiên đều lỗ, nên drawdown được đo từ 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;;
Đầu ra dự kiến (Python 3.12.10, pandas 3.0.5, matplotlib 3.11.1; chạy ngày 17 tháng Chín năm 2026):
Đã nạp 5 giao dịch đóng (1 dòng bỏ qua: không giờ đóng và không 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
Đã lưu: equity_curve.png
Phép tính để kiểm tra bằng tay: lãi 1.83 + 2.40 = 4.23 R, lỗ 1.00 + 1.08 = 2.08 R → PF 2.03; tổng 2.15 R / 5 = 0.43 R; đường −1.00 → −2.08 → −0.25 → −0.25 → 2.15, với đỉnh xuất phát 0 R → drawdown 2.08 R (không có điểm 0 R sẽ là 1.08 R — đây là khác biệt đứng sau định nghĩa phụ lục F). Đầu ra ứng với đúng tệp này và các phiên bản đã nêu; nếu khác, kiểm tra theo thứ tự dữ liệu (phân cách, dấu thập phân, mã hóa, thứ tự hàng), hằng số trong S1, mã, rồi phiên bản gói.
S4 · Tính khối lượng theo ATR
Python 3 · thư viện chuẩnKhối lượng lot cho khoảng stop k × ATR: số tiền rủi ro lấy từ vốn và tỷ lệ, khoảng cách lấy từ ATR, khối lượng làm tròn XUỐNG theo bước lot của tài khoản (các tham số lot_step và min_lot , cả hai mặc định 0.01) — để rủi ro DỰ KIẾN không vượt ngân sách. Lỗ thực có thể lớn hơn: phép tính không gồm trượt giá, gap qua stop, spread, hoa hồng và swap. Vốn và giá trị pip phải cùng tiền tài khoản; kiểm tra riêng khối lượng tối đa và yêu cầu ký quỹ trong thông số. Nhập ATR theo pip (EURUSD 0.0080 → 80; USDJPY 0.80 → 80; kích thước pip được nêu trong hồ sơ cặp tiền, phụ lục B); giá trị pip cho 1 lot có trong thông số công cụ (hoặc tính bằng công cụ ở phụ lục 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):
"Khối lượng lot cho stop atr_mult × ATR.\n atr_pips: ATR theo PIP, không phải đơn vị giá (EURUSD ATR 0.0080 -> 80; USDJPY ATR 0.80 -> 80 — kích thước pip của cặp).\n pip_value_per_lot: giá trị 1 pip cho 1.00 lot, theo đồng tiền tài khoản\n (ví dụ ~10 USD cho EURUSD trên tài khoản USD — kiểm tra thông số công cụ).\n lot_step / min_lot: bước khối lượng và tối thiểu của TÀI KHOẢN BẠN (0.01 phổ biến, không phổ quát).\n Làm tròn XUỐNG bội lot_step tính từ số không. Số học Fraction\n giữ đầu vào thập phân không phụ thuộc độ chính xác Decimal toàn cục.\n Rủi ro dự kiến không phải lỗ tối đa: mô hình không có trượt giá, khoảng trống, spread và swap."
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("Dùng giá trị số, không văn bản hay boolean (số thập phân Python dùng dấu chấm).")
decimals = tuple(Decimal(str(x)) for x in inputs)
if not all(x.is_finite() and x > 0 for x in decimals):
raise ValueError("Mọi đầu vào phải là số dương hữu hạn.")
c, p, a, k, v, step, minimum = map(Fraction, decimals)
if p > 100:
raise ValueError("risk_pct là phần trăm vốn (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": "Không có khối lượng được phép cho lot_step và min_lot này trong ngân sách rủi ro."}
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("Đầu vào vượt miền số đầu ra.") from None
if not all(math.isfinite(value) and value > 0 for value in result.values()):
raise ValueError("Đầu vào vượt miền số đầu ra.")
return result # float để hiển thị; không làm tròn thêm stop hay giá trị tiền
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}
Bạn nhận được: lot làm tròn xuống theo bước và số tiền rủi ro DỰ KIẾN tương ứng (trong mô hình không chi phí, ≤ ngân sách; lỗ thực có thể lớn hơn). Bước được tính từ không; kiểm tra tài khoản có dùng lưới khối lượng đó không. Stop và số tiền không bị làm tròn thêm: ví dụ ATR 0.26 pip × 1.25 cho 0.325 pip, không phải 0.3. Đầu ra trả dưới dạng float để đọc, còn số bước lot được tính bằng phân số chính xác; vẫn phải kiểm tra riêng bước giá tối thiểu của công cụ. Nếu điều chỉnh stop theo bước giá đó, hãy tính lại khối lượng. Đừng kỳ vọng quyết định có vào lệnh hay không — công cụ tính “bao nhiêu”, không phải “có nên”.
S5 · Biên độ ngày so với ATR có cảnh báo
Pine Script v6 · chỉ báoCông cụ nhận biết biến động (chỉ báo trong ngày): trên nến thời gian thực, nó cho biết thị trường đã “dùng” bao nhiêu phần trăm ATR ngày và cảnh báo khi vượt ngưỡng — lúc để xem kế hoạch, không phải đuổi giá. Dữ liệu ngày được lấy không nhìn trước (không dùng giá trị tương lai); trên nến lịch sử, request.security giữ giá trị ngày được xác nhận gần nhất đến cuối kỳ D tiếp theo, với kết quả mới của kỳ đó xuất hiện trên nến trong ngày cuối cùng. Trong thời gian thực, nó lấy biên độ và ATR đang hình thành của nến D hiện tại, nên số đọc trước có thể thay đổi sau tải lại (repainting). Một ngày là nến D của nhà cung cấp dữ liệu, không phải ngày lịch tại Europe/Warsaw. ATR trong mẫu số cũng thay đổi trong ngày; 100% không phải giới hạn giá có thể đi. Cách này không tái dựng được các lần vượt ngưỡng liên tiếp trong ngày hôm nay từ nến lịch sử.
//@version=6
indicator("Biên độ ngày so với ATR (công cụ nhận biết)", overlay=false)
if not timeframe.isintraday
runtime.error("Dùng biểu đồ trong ngày theo thời gian dưới 1D.")
atrLen = input.int(14, "Độ dài ATR", minval=2)
warnPct = input.int(80, "Cảnh báo khi biên độ ngày đạt % ATR", minval=10, maxval=200)
// Lịch sử: giá trị D xác nhận gần nhất, cập nhật CUỐI mỗi kỳ D.
// Thời gian thực: giá trị D đang hình thành; số đọc thời gian thực đã qua có thể vẽ lại sau tải lại.
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, "Biên độ ngày theo % ATR", linewidth=2)
hline(100, "100% ATR")
hline(warnPct, "Mức cảnh báo", linestyle=hline.style_dotted)
alertcondition(ta.crossover(rangePct, warnPct),
title="Biên độ đạt % ATR",
message="Biên độ ngày đã đạt % ATR bạn đặt — đọc lại kế hoạch trước khi vào mới.")
Bạn nhận được: khung dưới biểu đồ và điều kiện cảnh báo — tự tạo cảnh báo trong nền tảng sau khi thêm chỉ báo, chọn “Range reached % of ATR”. Dùng nến trong ngày chuẩn dựa trên thời gian; dữ liệu Heikin Ashi/Renko có thể khác. Số đọc thiếu (na) nghĩa là ATR hoặc dữ liệu cần thiết chưa có, không phải 0%. Điều kiện cần chuyển từ giá trị ≤ ngưỡng sang giá trị > ngưỡng: chỉ tiếp tục ở trên ngưỡng không kích hoạt cảnh báo mới. “Once Per Bar Close” giới hạn cảnh báo vào lúc đóng nến trong ngày, nhưng không xác nhận toàn bộ nến D. Tạo lại cảnh báo sau khi đổi tham số. Đừng kỳ vọng tín hiệu hướng — số đọc cao nói “giá đã di chuyển”; playbook quyết định bạn làm gì tiếp.
S6 · Khung giờ theo kế hoạch giao dịch trên biểu đồ
Pine Script v6 · chỉ báoMục 3 của kế hoạch (phụ lục E) được vẽ trên biểu đồ: tô giờ bạn ĐƯỢC PHÉP mở vị thế và cảnh báo khi khung giờ kết thúc. Nhập giờ theo múi Europe/Warsaw — mã IANA xử lý CET/CEST. Mặc định khung áp dụng thứ Hai đến thứ Sáu; tùy chọn mở rộng sang mọi ngày. Tô nền chỉ xác nhận thời gian trong kế hoạch, không xác nhận điều kiện vào lệnh khác. Dùng nến trong ngày chuẩn dựa trên thời gian.
//@version=6
indicator("Khung phiên theo kế hoạch giao dịch", overlay=true)
if not timeframe.isintraday
runtime.error("Dùng biểu đồ trong ngày theo thời gian dưới 1D.")
tz = input.string("Europe/Warsaw", "Múi giờ các khung")
win1 = input.session("0900-1200", "Khung 1")
win2 = input.session("1400-1700", "Khung 2")
weekdaysOnly = input.bool(true, "Chỉ thứ Hai đến thứ Sáu")
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="Trong khung kế hoạch")
windowJustClosed = inWin[1] and not inWin
alertcondition(windowJustClosed,
title="Khung kế hoạch đã đóng",
message="Khung giao dịch vừa đóng — chỉ quản lý vị thế mở, không vào mới (kế hoạch, mục 3).")
Bạn nhận được: nền tô trong giờ giao dịch và điều kiện cảnh báo khung giờ đóng (“Plan window closed” — tạo cảnh báo trong nền tảng sau khi thêm chỉ báo). Cảnh báo nhận nến đầu tiên ngoài khung sau một nến trong khung, nên không bảo đảm thông báo đúng thời điểm kết thúc: không có nến mới và cập nhật dữ liệu thì không kiểm tra. Dùng khung thời gian có giờ mở và đóng trùng ranh giới cửa sổ. Ví dụ trên M15, với cửa sổ 09:00–12:00 và có nến 12:00, tô nền kết thúc lúc 12:00, điều kiện hoạt động trên nến đầu tiên ngoài khung đó. “Once Per Bar” có thể báo ở cập nhật đầu; “Once Per Bar Close” chỉ khi nến đóng. Các khung chồng nhau tạo hợp: hết khung đầu không đóng khung thứ hai. Tạo lại cảnh báo sau khi đổi giờ. Đừng kỳ vọng chặn lệnh — chỉ báo nhắc kế hoạch; checklist trước giao dịch thực thi nó.
Sáu đoạn mã có tiêu đề trong một tệp văn bản, hướng dẫn thiết lập và phiên bản thư viện, tiếp theo là CSV thử và đầu ra dự kiến — để lưu cạnh nhật ký hoặc trong kho mã riêng. TXT ghép nhiều ngôn ngữ lập trình: không chạy cả tệp như Python. Chọn S1+S2+S3, S4 độc lập hoặc một chỉ báo Pine.
Câu hỏi thường gặp
Vì sao tên kỹ thuật giữ tiếng Anh còn chú thích được dịch?
Tên API, định danh, cú pháp và thông báo lỗi thư viện giữ tiếng Anh để khớp tài liệu pandas và Pine Script; chú thích và nhãn đầu ra cho người đọc trong bản này dùng tiếng Việt. Bản gốc của khóa học tiếng Ba Lan dùng chú thích tiếng Anh cho bộ mã thư viện: phần mô tả tiếng Ba Lan giải thích mã làm GÌ và khi nào dùng, chú thích bên trong giải thích LÀM THẾ NÀO. Xưởng AI cũng nêu quy ước đó trong ngữ cảnh mã (phụ lục H, P3). Ngoại lệ của bản prompt P5 tiếng Ba Lan — chú thích tiếng Ba Lan trong mã tạo riêng — áp dụng mã dùng một lần, không phải quy ước của thư viện gốc. Bản địa hóa này dịch phần dành cho người đọc và giữ nguyên API cùng logic.
Chạy các đoạn Python như thế nào?
11.8 hướng dẫn từng bước cài Python, môi trường và gói — pandas và matplotlib là đủ cho bộ mã này. Ghép S1–S3 vào một tệp, analiza_dziennika.py (S1 ở đầu), rồi chạy python analiza_dziennika.py trong thư mục chứa bản xuất nhật ký; S4 chạy độc lập. Đường dẫn tương đối CSV_PATH trỏ đến thư mục làm việc của terminal. Bắt đầu với CSV thử và phân tích bản sao nhật ký thật; equity_curve.png bị ghi đè ở lần chạy tiếp theo. Nếu terminal báo lỗi bạn chưa hiểu, dán mã và toàn bộ thông báo vào rà soát P3 trong phụ lục H, thay vì đoán.
Có thể sửa và mở rộng các đoạn mã không?
Đó là mục đích của bộ KHỞI ĐẦU này. Mở rộng tự nhiên gồm chỉ số theo setup (nhóm theo cột setup trước khi gọi hàm S2), lọc error_code để tính kỳ vọng khi thực thi không lỗi, hoặc đường riêng cho nhóm A+/B. Hai quy tắc khi sửa: đưa mọi thay đổi qua rà soát P3 (nhất là phần có request.security trong Pine), và quản lý phiên bản cả định nghĩa chỉ số lẫn quy tắc chiến lược. Sửa lỗi tính toán ngay và tính lại các giai đoạn so sánh bằng cùng phương pháp; ghi thay đổi quy tắc chiến lược trong biên bản kiểm thử (phụ lục N) và kiểm tra trên dữ liệu mới. Hết quý tự nó không biện minh cho thay đổi, cũng như đang giữa quý không biện minh cho việc giữ lỗi.
Vì sao bộ mã không có chiến lược hoặc EA?
Cùng lý do xưởng AI không tạo tín hiệu: chiến lược có sẵn trên mạng có lợi thế chưa biết, giả định chưa rõ và không gắn với kế hoạch của bạn — EA thực thi logic người khác trên tài khoản là giao quyết định mà chỉ bạn trả giá. Mã trong khóa học củng cố quy trình (đo lường, trực quan hóa, bám kế hoạch), không thay thế nó. Nếu muốn tự động hóa chiến lược đã kiểm thử của mình, lộ trình đi qua backtest trong 15.4, biên bản kiểm thử phụ lục N và rà soát P3, không qua việc sao chép script “có lãi”.
math.floor trong S4 thay cho round: máy làm tròn xuống không tranh luận; người làm tròn lên kèm lý do.Tài liệu khóa học liên quan
- 11.8 Python trong giao dịch — thiết lập môi trường, script đầu tiên và làm việc với gói
- Phụ lục F — bảng nhật ký — định dạng CSV mà S1–S3 đọc, cùng chỉ số dưới dạng công thức bảng tính
- Phụ lục H, prompt P3 — rà soát mọi chỉnh sửa mã này (nhìn trước, repainting, lỗi logic)
- Phần công cụ — các phép tính — tính giá trị pip và khối lượng vị thế trong trình duyệt để kiểm tra S4
- Phụ lục E — mẫu kế hoạch — khung giờ và giới hạn mà S6 vẽ trên biểu đồ
- 15.10 Kiểm toán chiến lược — diễn giải có kỷ luật các con số bộ mã tạo ra
Nguồn
- Tài liệu: pandas 3.0.5 và matplotlib 3.11.1 (các hàm dùng trong S1–S3); Python: Đọc CSV và Phép toán Fraction (kiểm tra định dạng và tính chính xác số bước lot) — S1–S4 được chạy trên dữ liệu tổng hợp ngày 17 tháng Chín năm 2026 bằng Python 3.12.10; TradingView Pine Script v6: khung thời gian và dữ liệu khác, phiên, thời gian và múi giờ, cảnh báo (request.security với tham số lookahead và repainting, hline, input.session, alertcondition) — mã S5–S6 đã được rà soát theo tài liệu, chưa biên dịch.
- Nội bộ: 11.8 Python trong giao dịch (môi trường), 15.9 (định nghĩa chỉ số và định dạng nhật ký), 15.10 (nguyên tắc rút kết luận) — bộ mã là cách triển khai cô đọng, thực hành của các phần đó.
- Van K. Tharp, Trade Your Way to Financial Freedom, ấn bản thứ 2, McGraw-Hill 2007 — bội số R và kỳ vọng, ngôn ngữ chung của S2, bảng F và prompt P5.