OptiNod Academy

Cách backtest trên TradingView — từ thiết lập đến phân tích CSV

Áp dụng chiến lược, đặt vốn, phí, trượt giá và thời gian; xử lý trường hợp không có giao dịch, đọc kết quả và phân tích CSV. Ghi lại điều kiện để so sánh lần kiểm tra tiếp theo.

Lần backtest đầu tiên cần lưu cả thiết lập lẫn lịch sử giao dịch. Những điều kiện đó giúp bạn so sánh kết quả lần sau.


Chiến lược có thể không tạo giao dịch, hoặc lợi nhuận biến mất sau khi thêm phí. Hãy bắt đầu bằng quy tắc tạo lệnh và khối lượng lệnh.


Backtest trên TradingView áp dụng quy tắc giao dịch vào dữ liệu quá khứ để tạo giao dịch mô phỏng. Dấu mua/bán, khớp lệnh thực và giao dịch trong báo cáo chiến lược là các bản ghi khác nhau.


Thực hiện theo thứ tự: áp dụng chiến lược → đặt chi phí và thời gian → xem giao dịch đầu tiên → đọc kết quả → lưu danh sách giao dịch. Sau đó phân tích CSV trong OptiNod và dùng các giao dịch gây lỗ để chọn bước kiểm tra tiếp theo.


Áp dụng chiến lược để xem cả lệnh và kết quả


Bắt đầu bằng biểu đồ nến thông thường. Chọn mã có tên sàn và khung thời gian. Thêm chiến lược bạn có quyền sử dụng, ghi lại tên, phiên bản mã nguồn và đầu vào. Chỉ thêm chỉ báo như đường trung bình không tạo giao dịch backtest. Chiến lược cần khai báo strategy() và lệnh tạo giao dịch mô phỏng.


Tài liệu chính thức hiện gọi bảng dưới biểu đồ là Strategy report, với các thẻ Metrics và Trades. Tùy ngôn ngữ và phiên bản giao diện, bạn có thể thấy tên cũ như Strategy Tester, Overview và List of Trades. Tìm riêng danh sách giao dịch và các chỉ số hiệu suất. Tài liệu chiến lược chính thức


Dùng nến thông thường giúp hạn chế việc trộn giá tổng hợp vào giả định khớp lệnh. Sau khi thêm chiến lược, xem có bản ghi vào và thoát lệnh hay chưa.


Ví dụ là OptiNod Learn - SMA 10/30 Backtest Guide v1.0.0. Chúng tôi chọn NASDAQ:AAPL, nến thông thường và 1D; nguồn trên màn hình là NASDAQ by Cboe One. Ngày kiểm tra là 2026-10-01. Đây là mã tự viết để học: vào long khi SMA 10 cắt lên SMA 30, đóng khi cắt xuống. Không có stop, mục tiêu lợi nhuận hay cảnh báo giao dịch thực riêng; đây không phải đề xuất dựa trên hiệu suất.


  1. Mở script mới trong Pine Editor của TradingView và dán mã dưới đây.
  2. Áp dụng vào biểu đồ, khớp NASDAQ:AAPL, 1D và nến thông thường.
  3. Đối chiếu thời gian và Base Entry Amount trong Inputs, rồi vốn, chi phí và thiết lập khớp trong Properties.
  4. Mở danh sách giao dịch và chỉ số, so sánh với kết quả quan sát dưới đây trong cùng điều kiện.

//@version=6
// OptiNod Learn educational example v1.0.0. AAPL standard candles, 1D.
// Simulated orders only. No alerts or webhook payloads are defined.
strategy("OptiNod Learn - SMA 10/30 Backtest Guide", overlay=true, pyramiding=0, initial_capital=10000, currency=currency.USD, default_qty_type=strategy.fixed, default_qty_value=1, commission_type=strategy.commission.percent, commission_value=0.05, slippage=1, margin_long=100, margin_short=100, process_orders_on_close=false, calc_on_every_tick=false, calc_on_order_fills=false, use_bar_magnifier=false)

// 0 - Period / Capital: first input group, before signal and visual inputs.
string G_CAP = "0 · Period · Capital"
int startTime = input.time(1704067200000, "Start Time", group=G_CAP, inline="win") // 2024-01-01 00:00 UTC
int endTime = input.time(1767225600000, "End Time", group=G_CAP, inline="win", tooltip="Entries use bar opening times in [start, end). An open position is closed at the first calculated bar at or after end; market fills normally occur on the next available tick.") // 2026-01-01 00:00 UTC
float leverage = input.float(1.0, "Leverage", minval=1.0, maxval=1.0, step=1.0, group=G_CAP, tooltip="This educational stock example is unleveraged: 1x only. Margin requirement is 100%.")
float baseAmount = input.float(1000.0, "Base Entry Amount", minval=0.0, group=G_CAP, inline="amt")
string amountUnit = input.string("$", "", options=["%", "$"], group=G_CAP, inline="amt", tooltip="Margin budget per entry in USD. % uses current strategy equity; $ uses a fixed amount. Whole-share rounding makes actual exposure no greater than the budget at the signal close.")
bool useVarSizing = input.bool(true, "Variable Position Sizing", group=G_CAP, tooltip="The standard header keeps this control. This simple example always uses multiplier 1, so toggling it does not change sizing.")

string G_SIGNAL = "1 · Moving Averages"
int fastLength = input.int(10, "Fast SMA", minval=1, group=G_SIGNAL)
int slowLength = input.int(30, "Slow SMA", minval=1, group=G_SIGNAL)

string G_VIEW = "2 · Visuals"
bool showAverages = input.bool(true, "Show averages", group=G_VIEW)
color fastColor = input.color(#10b981, "Fast", group=G_VIEW, inline="palette")
color slowColor = input.color(#9aa0b5, "Slow", group=G_VIEW, inline="palette")

// AAPL whole shares. Quantity uses the signal close, not an unknowable future fill.
qtyFor(float stateMult) =>
    float margin = (amountUnit == "%" ? strategy.equity * baseAmount / 100.0 : baseAmount) * (useVarSizing ? stateMult : 1.0)
    math.floor(math.max(margin, 0.0) * leverage / (close * syminfo.pointvalue))

bool inWindow = time >= startTime and time < endTime
float fastSma = ta.sma(close, fastLength)
float slowSma = ta.sma(close, slowLength)
bool longSignal = ta.crossover(fastSma, slowSma)
bool exitSignal = ta.crossunder(fastSma, slowSma)
float entryQty = qtyFor(1.0)

if inWindow and longSignal and strategy.position_size == 0 and entryQty > 0
    strategy.entry("Long", strategy.long, qty=entryQty, comment="Long")

if strategy.position_size > 0 and time >= endTime
    strategy.close("Long", comment="Time exit")
else if strategy.position_size > 0 and exitSignal
    strategy.close("Long", comment="Exit")

// Layout: Minimal Overlay. Two averages explain the educational crossover.
plot(showAverages ? fastSma : na, "Fast SMA", color=fastColor, linewidth=2)
plot(showAverages ? slowSma : na, "Slow SMA", color=slowColor, linewidth=1)

Số lượng bằng ngân sách 1,000 USD chia giá đóng cửa nến tín hiệu, làm tròn xuống số cổ phiếu nguyên. Giá trị khớp không nhất thiết bằng đúng 1,000 USD. Gap nến sau và trượt giá có thể thay đổi giá trị khớp. Đòn bẩy cố định 1x. Variable Position Sizing bật nhưng hệ số luôn là 1, nên bật hay tắt không đổi số lượng.


Đầu vào thời gian và vốn thực tế
Đầu vào thời gian và vốn thực tếUTC 00:00 hiện thành 09:00 trên màn hình giờ Hàn Quốc. (2026-10-01)

Đặt chi phí và khối lượng trước khi so sánh


Trong thiết lập chiến lược, mở Properties để đặt vốn, khối lượng, phí và trượt giá. Bảng dưới ghi thiết lập và đơn vị đã dùng trong lần chạy thực tế.


MụcGiá trị thực dùngĐơn vịVì sao ảnh hưởng kết quả
Vốn ban đầu/tiền tệ10,000 USDUSDVốn khởi đầu và mốc tỷ suất
Base Entry Amount1,000, đơn vị $USD/ngân sách vào lệnhMã tính cổ phiếu nguyên từ giá đóng nến tín hiệu
Đòn bẩy/ký quỹ1x; long và short 100%hệ số, %Lệnh mô phỏng không đòn bẩy trong vốn khả dụng
Phí0.05%/lệnh0.05% giá trị mỗi lần vào và thoát
Trượt giá1tickÁp dụng vào giá khớp thị trường và stop
Chi tiết nếnDefault (4 ticks per bar)4 điểm giá/nếnDùng giả định OHLC mặc định khi khớp lịch sử
Thực thi scriptOn bar closeđóng nếnTính giao cắt khi nến đóng
Độ trễ thực thi lệnhOne tick1 tickLệnh thị trường khớp tại tick khả dụng tiếp theo

Chênh lệch giá bằng số tick × bước giá tối thiểu của mã. Khối lượng theo tỷ lệ vốn thay đổi theo vốn khi vào lệnh. Nếu mã nguồn chỉ định số lượng cho từng lệnh, đổi khối lượng mặc định có thể không đổi lệnh đó. Định nghĩa thuộc tính chính thức


Ghi cả ký quỹ, tính toán lại và tùy chọn khớp lệnh. Tách tác động của chi phí và khối lượng khỏi tác động của việc đổi quy tắc giao dịch.


Properties hiện khối lượng mặc định 1, nhưng mã truyền qty vào strategy.entry(), nên số lượng thực đến từ ngân sách trong Inputs. Đối chiếu Default detalization và Script execution trong báo cáo với Properties trong thiết lập chiến lược.


Thiết lập vốn, phí và khớp thực tế
Thiết lập vốn, phí và khớp thực tếĐối chiếu vốn 10,000 USD, phí 0.05%, On bar close và chi tiết nến mặc định. (2026-10-01)

Đọc thời gian cùng dữ liệu biểu đồ


Backtest thông thường chạy trên dữ liệu đã tải vào biểu đồ. Đầu vào ngày của chiến lược giới hạn lệnh trong dữ liệu đó, không tải thêm lịch sử cũ. Nếu có đầu vào thời gian, đặt ngày bắt đầu và kết thúc, rồi đối chiếu thời điểm giao dịch với khoảng thời gian dự định.


Lựa chọn Testing period và Deep Backtesting là các tính năng riêng. Ghi phạm vi tài khoản hỗ trợ và thời gian kết quả hiển thị. Không mặc định mọi tài khoản đều có lựa chọn khoảng thời gian. Hướng dẫn về thời gian và dữ liệu


Ghi múi giờ hiển thị, phiên của sàn, nến đầu tiên và giai đoạn chuẩn bị tính toán. Cùng đầu vào ngày chưa có nghĩa là cùng phạm vi dữ liệu.


Inputs quan sát được là 2024-01-01 00:00 UTC đến 2026-01-01 00:00 UTC. Màn hình theo giờ Hàn Quốc hiện 09:00. Chỉ tạo lệnh mới khi thời điểm mở nến tín hiệu từ lúc bắt đầu trở đi và trước lúc kết thúc.


Phạm vi tính toán báo cáo là 1980-12-12–2026-09-30, khác khoảng vào lệnh bị mã giới hạn. Lần vào đầu tiên thực tế là 2024-01-30, lần đóng cuối 2025-12-23. Các nến đã tải trước đó được dùng để chuẩn bị tính toán; không đọc phạm vi báo cáo như khoảng vào lệnh.


Nếu còn vị thế sau điểm kết thúc, mã yêu cầu đóng ở nến được tính đầu tiên có thời điểm mở bằng hoặc sau điểm đó, rồi khớp tại tick khả dụng tiếp theo. Không thanh lý đúng dấu thời gian kết thúc. Lệnh vào tạo trong khoảng cũng có thể khớp ngoài khoảng trên nến tiếp theo.


Khi không có giao dịch, thu hẹp đường tạo lệnh trước


Kiểm tra script là chiến lược và có lệnh giao dịch. Nếu biểu đồ hiện lỗi chạy, mở dấu lỗi để đọc thông báo. Sau đó xem điều kiện ngày có giao với dữ liệu không và điều kiện vào lệnh có xuất hiện không.


Khối lượng bằng 0 hoặc vốn và ký quỹ không đáp ứng quy mô lệnh cũng có thể ngăn giao dịch. Giá trị hợp đồng tương lai phụ thuộc giá trị điểm và số lượng, nên giá trên biểu đồ không đủ để kết luận vốn đáp ứng.


Thứ tự kiểm tra giao dịch bằng 0: loại script và lỗi chạy → dữ liệu và ngày → điều kiện vào lệnh → khối lượng và vốn. Đổi từng mục để xem giao dịch có xuất hiện không. Khi có giao dịch đầu tiên, đối chiếu thời gian vào/thoát, giá, khối lượng và tín hiệu với biểu đồ.


Dùng nguyên nhân chiến lược không tạo lệnh để thu hẹp nguyên nhân trước khi đọc hiệu suất. Một lần chạy không có giao dịch và một lần chạy bị lỗ cần bước tiếp theo khác nhau.


Đặt cả Fast SMA và Slow SMA thành 10 thực tế tạo thông báo “This report requires trade data”. Hai đường giống nhau không giao cắt nhau, nên điều kiện lệnh không xảy ra. Khôi phục Slow SMA về 30 để trở lại giao cắt 10/30. Đây là trường hợp không thỏa điều kiện; tăng vốn không giải quyết được.


Không có giao dịch với SMA 10/10
Không có giao dịch với SMA 10/10Hai đường giống nhau không giao cắt. Khôi phục Slow SMA về 30. (2026-10-01)

Sau PnL ròng, quay lại giao dịch gây lỗ


Net PnL đã phản ánh phí được thiết lập. Trừ Commission paid lần nữa sẽ tính phí hai lần. Đọc Open PnL riêng với kết quả đã chốt. Cách xử lý phí


Chỉ sốCơ sở đọcĐiều chưa thể biết từ riêng giá trị này
Giao dịch đã đóngĐếm giao dịch đã vào và thoátTần suất tương lai có giống hay không
PFTổng PnL giao dịch thắng ÷ trị tuyệt đối tổng PnL giao dịch thuaLợi nhuận có tập trung vào ít giao dịch hoặc giai đoạn không
Kết quả trung bìnhNet PnL ÷ số giao dịch đã đóngPhân phối kết quả và quy mô lỗ lớn
Drawdown tối đaGhi cơ sở intrabar/close-to-close và mẫu số của %Drawdown tương lai có nằm trong phạm vi đó không

Số giao dịch, PF và Expected payoff không gồm vị thế mở. Nếu tổng lỗ bằng 0, không có PF hữu hạn để so sánh thông thường. Xem thời điểm và phân phối kết quả thay vì đặt PF đạt chuẩn hoặc số giao dịch tối thiểu chung cho mọi chiến lược.


Drawdown tối đa intrabar bao gồm chuyển động giá trong nến khi đang giữ vị thế. Nó có thể khác drawdown chỉ tính từ PnL tích lũy của giao dịch đã đóng. Phân biệt % vốn ban đầu với % dùng mẫu số khác. Đọc drawdown intrabar và drawdown theo vốn ban đầu, rồi mở biểu đồ quanh các khoản lỗ lớn.


Chúng tôi đối chiếu lần chạy TradingView với CSV giao dịch tiếng Anh. Có 18 dòng vào/thoát và 9 giao dịch đã đóng. Cả hai dòng lặp lại PnL giao dịch nên chỉ dùng dòng thoát để kiểm tra.


MụcKết quả quan sátÝ nghĩaĐiều chưa thể biết từ riêng giá trị này
Giao dịch đã đóng9; 3 thắng, 6 thuaMẫu giao dịch hoàn tấtTần suất và khả năng lặp lại tương lai
Total PnL169.84 USD, +1.70%Khớp tổng Net PnL các dòng thoátGiai đoạn khác có cùng kết quả không
Profit factorMàn hình 1.81; CSV khoảng 1.81015Kiểm tra bằng 379.48 ÷ 209.64Mức phụ thuộc vào số ít giao dịch thắng
Expectancy18.87 USD169.84 ÷ 9 ≈ 18.87111Quy mô lỗ từng giao dịch và phân phối
Max drawdownMàn hình 239.05 USD, 2.35%Drawdown theo phép tính TradingView đóCó thể dựng lại đường intrabar từ CSV hay không

Tổng PnL dòng thoát là 169.84 USD. Tổng lời 379.48 USD và trị tuyệt đối tổng lỗ 209.64 USD dùng các trường CSV đã làm tròn. Tổng lỗ trên màn hình TradingView là 209.63 USD, lệch 0.01 USD; cộng các dòng đã làm tròn có thể hơi khác hiển thị tổng hợp nội bộ.


Không mô tả 2.35% hiển thị là kết quả của 239.05 ÷ 10,000: phép tính đó khoảng 2.3905%. Giữ riêng cơ sở tính của chỉ số drawdown. Tỷ suất +1.70% khớp với 169.84 ÷ 10,000 × 100 = 1.6984% sau làm tròn.


Kết quả TradingView quan sát
Kết quả TradingView quan sátGhi 9 giao dịch đóng, Net PnL 169.84 USD và PF 1.81. (2026-10-01)

Nhập CSV giao dịch để xem lại giai đoạn lỗ


Lưu CSV bằng Download trong Trades hoặc List of Trades. Xuất chỉ số và xuất danh sách giao dịch chứa thông tin khác nhau. Dù có báo cáo đầy đủ XLSX, đầu vào OptiNod trong hướng dẫn này là CSV danh sách giao dịch. Hướng dẫn xuất chính thức


Mở tệp để xem số giao dịch, thời gian vào/thoát và Net PnL. Lưu tên tệp cùng chiến lược, mã, khung thời gian và thiết lập. Đếm mọi dòng vào và thoát có thể khác số giao dịch đã hoàn tất.


Nhập CSV vào phân tích OptiNod, rồi đối chiếu số giao dịch đã đóng và Net PnL với báo cáo gốc trước. Danh sách có tiêu đề cột tiếng Hàn hoặc tiếng Anh được hỗ trợ. Nếu ngôn ngữ khác không được nhận diện, đổi ngôn ngữ hiển thị TradingView sang tiếng Hàn hoặc tiếng Anh rồi xuất lại. Tệp chỉ có giao dịch chưa đóng không dùng được cho phân tích giao dịch đã đóng.


Có thể bắt đầu phân tích không cần đăng nhập; lưu vào tài khoản cần đăng nhập hoặc đăng ký. Tìm giao dịch và giai đoạn góp phần gây lỗ, rồi quay lại biểu đồ và điều kiện của chúng. Drawdown từ CSV không tái tạo chính xác drawdown tối đa intrabar gốc, nên đọc cả cơ sở tính toán.


Chúng tôi nhập trực tiếp 18 dòng CSV tiếng Anh vào OptiNod và xác nhận phân tích mở. Vị thế hoàn tất hiện 9, PnL thực hiện 170 USD, PF 1.81. Hiển thị 170 USD là làm tròn từ 169.84 USD. Giao dịch đầu vào ngày 2024-01-30, thoát 2024-02-12, PnL -13.65 USD.


239 USD của OptiNod được ghi rõ là drawdown ước tính từ lịch sử giao dịch. Các giá trị làm tròn gần nhau không có nghĩa MDD intrabar chính thức 239.05 USD của TradingView đã được dựng lại chính xác. Mở giao dịch lỗ đầu tiên và đối chiếu điều kiện vào, thoát và chi phí với biểu đồ gốc.


Phân tích OptiNod cùng CSV
Phân tích OptiNod cùng CSVHiện 9 vị thế hoàn tất, PF 1.81 và drawdown ước tính từ giao dịch. (2026-10-01)

Tách điều kiện thay đổi khỏi điều kiện giữ nguyên


Khi so sánh chi phí, giữ nguyên mã nguồn, đầu vào, mã, khung thời gian, ngày và khối lượng. Khi so sánh giai đoạn, giữ nguyên quy tắc và chi phí rồi đổi ngày. Chia một tệp theo thời gian khác với chạy lại chiến lược trên một giai đoạn dữ liệu mới.


Đọc tiếp trượt giá, phí và thanh khoản về chi phí và khớp lệnh, lookahead và repainting về thời điểm tín hiệu, và quá khớp về độ ổn định quanh thiết lập. Phân tích walk-forward nói về lặp lại quy trình ở giai đoạn không dùng để tối ưu; backtest và giao dịch thực nói về điểm bắt đầu khác nhau trong giao dịch thực.


Khi lưu lần chạy tiếp theo, viết một dòng về điều đã đổi. Điều kiện và lịch sử được giữ lại giúp bạn quay về các giao dịch tạo ra chênh lệch.

Kiểm tra backtest của bạn

Tải lên CSV kết quả tối ưu hóa hoặc danh sách giao dịch của chiến lược TradingView để xem các chỉ số hiệu suất cùng kết quả kiểm tra độ bền. Không cần đăng nhập để phân tích.

Phân tích tệp kết quả Xem báo cáo mẫu