מדריך · בודק אסטרטגיות

קונסולת הבדיקה לאחור: בדיקת אסטרטגיות מסחר בקוד

לכל גרף יש כפתור אסטרטגיה. הוא פותח קונסולה שמריצה אסטרטגיה על נרות העבר ומציגה כל עסקה על הגרף, את הרווח, הירידה מהשיא, אחוז ההצלחה ועקומת הון מול קנה והחזק. התחילו באסטרטגיה מובנית, ואז כתבו משלכם בכמה שורות JavaScript.

פתיחת הקונסולה על EURUSD מעבר לדוגמאות

בטוח מעצם התכנון. הסקריפט שלכם רץ רק בדפדפן שלכם, בארגז חול בלי גישה לאינטרנט: הוא יכול לקרוא את הנרות שהוא מקבל ותו לא (לא את החשבון שלכם, לא את האתר הזה, לא אתרים אחרים). שום דבר שאתם כותבים לא רץ על השרתים שלנו.

התחלה בדקה

  1. פתחו כל גרף, למשל EURUSD, ובחרו את טווח הזמן לבדיקה (H1, ‏D1…).
  2. לחצו אסטרטגיה בסרגל הכלים של הגרף. הקונסולה נפתחת מתחת לגרף.
  3. בחרו אסטרטגיה מובנית, למשל חציית ממוצעים נעים. היא רצה מיד: חצים על הגרף מסמנים כל כניסה ויציאה.
  4. שנו פרמטר (למשל הממוצע האיטי מ-30 ל-50): הבדיקה רצה שוב מעצמה.
  5. קראו את סקירה לסיכומים, את עסקאות לכל עסקה, ואת עקומת הון לחשבון לאורך זמן.
  6. לחצו עריכת עותק כדי להפוך אותה לסקריפט משלכם, שנו ולחצו הרצת בדיקה (או Ctrl+Enter).

הקונסולה, חלק אחר חלק

חלקמה זה עושה
רשימת אסטרטגיותמובנות: שש אסטרטגיות מוכנות (חציית ממוצעים נעים, היפוך RSI, חזרה לממוצע ברצועות בולינגר, חציית אות MACD, פריצת דונצ'יאן, SuperTrend). האסטרטגיות שלי: אלה ששמרתם (היכנסו לחשבון). סקריפט חדש… מתחיל אחד ריק.
הצגת הקוד / עריכת עותקהצגת הקוד מראה בדיוק מה אסטרטגיה מובנית עושה. עריכת עותק מעתיקה אותה לעורך כסקריפט משלכם, מוכנה לשינוי.
קלטיםכל input(…) בסקריפט הופך כאן לשדה (מספר או רשימה). שינוי של אחד מריץ את הבדיקה מחדש. ברירות מחדל מחזיר אותם.
הגדרותהון, גודל פקודה, עלויות, כמה נרות והאם עסקאות שורט מותרות (למטה).
עורךה-JavaScript של האסטרטגיה. Tab מזיח, Ctrl/⌘+Enter מריץ. שגיאה מציגה את ההודעה ומספר השורה.
אסמכתהרשימה קצרה של כל מה שסקריפט יכול להשתמש בו, ישירות בקונסולה. העמוד הזה הוא הגרסה הארוכה.
שמירה / שמירה בשם…שומר את הסקריפט, שמו, הפרמטרים וההגדרות בחשבון שלכם (נקודה על שמירה • מסמנת שינויים שלא נשמרו). האסטרטגיות שלכם מופיעות בכל גרף.
לשוניות תוצאותסקירה, עסקאות (עם הורדת CSV), עקומת הון ו-Log. עסקאות וקווים משורטטים מופיעים גם על הגרף; לחצו על עסקה כדי לקפוץ אליה.

הגדרות

הגדרהמשמעותערך התחלתי טוב
הון התחלתיהחשבון שאיתו הבדיקה מתחילה, במטבע המחיר (ל-EURUSD: דולרים).10,000
גודל הפקודה% מההון: כל עסקה משתמשת בחלק הזה של החשבון באותו רגע (100% = כל החשבון, בלי מינוף). יחידות: כמות קבועה (במט"ח, יחידות של מטבע הבסיס: 100,000 = לוט סטנדרטי). סקריפט יכול לקבוע גודל משלו לכל פקודה עם { qty }.100% מההון, או לוט קבוע
עמלה % לכל צדעמלה באחוזים מהערך הנסחר, שנגבית בכניסה ושוב ביציאה.0.002–0.01 למט"ח, 0.05–0.1 למניות ולקריפטו
החלקה / מרווח (מחיר)מתווסף לרעתכם בכל ביצוע, ביחידות מחיר. הנרות הם מחירי bid, אז הזינו כאן את המרווח הטיפוסי כדי שהקניות יהיו מציאותיות.EURUSD 0.00010 (פיפ אחד), זהב 0.30
נרותעל הגרף: הנרות שנטענו על המסך. כשאתם מחוברים, בחרו עד 5,000 … 100,000 כדי לטעון עוד היסטוריה של אותו טווח זמן (האתר מאפשר עד 20,000).כמה שיותר: יותר נרות, יותר עסקאות, מספרים אמינים יותר
לאפשר עסקאות שורטכבוי: short() רק סוגר פוזיציית לונג ולעולם לא פותח שורט. שימושי לבדוק רק את צד הלונג בלי לערוך את הסקריפט.פעיל למט"ח, כבוי להשקעה בלונג בלבד

קריאת התוצאות

מספרמה זה אומר לכם
רווח נקיההון הסופי פחות ההון ההתחלתי, אחרי עמלה והחלקה; גם באחוזים מההון.
קנה והחזקכמה הייתה מניבה פשוט קנייה בנר הראשון והחזקה עד האחרון. אסטרטגיה שלא מנצחת את זה, או מנצחת רק עם ירידה עמוקה בהרבה, מוסיפה מעט.
ירידה מקסימליתהירידה הגדולה ביותר של ההון משיא, בכסף ובאחוזים. הכאב שהייתם צריכים לעבור. סוחרים רבים מסתכלים על רווח נקי ÷ ירידה מקסימלית מהשיא.
עסקאות, % מוצלחותכמה עסקאות נסגרו ואיזה חלק מהן הרוויח. אחוז הצלחה נמוך זה בסדר אם העסקאות המרוויחות גדולות בהרבה מהמפסידות.
פקטור רווחרווח גולמי ÷ הפסד גולמי. מעל 1 מרוויח כסף; 1.3–2 אופייני לאסטרטגיות יציבות; ערכים גבוהים מאוד על מעט עסקאות הם בדרך כלל מזל.
עסקה ממוצעת, רווח ממוצע, הפסד ממוצערווח ממוצע לעסקה, והגודל הטיפוסי של מרוויחות ומפסידות. השוו את העסקה הממוצעת לעלויות שלכם.
הרווח / ההפסד הגדול ביותר, עסקאות מפסידות ברצףהקיצוניים. עסקה מרוויחה ענקית אחת שנושאת את כל התוצאה היא סימן אזהרה.
יחס שארפתשואה ליחידת תנודתיות, בחישוב שנתי משינויי ההון מנר לנר. מעל 1 טוב, מעל 2 טוב מאוד (ונדיר).
זמן בשוקהחלק של הנרות עם פוזיציה פתוחה. פחות זמן לאותו רווח פירושו פחות סיכון.
לונג / שורטעסקאות, רווח ואחוז הצלחה של כל צד בנפרד: לעתים קרובות צד אחד עושה את כל העבודה.

לשונית עסקאות מפרטת כל עסקה עם הכיוון, זמן ומחיר הכניסה והיציאה, הגודל, הרווח בכסף ובאחוזים, כמה נרות נמשכה, למה נסגרה (אות, סטופ לוס, טייק פרופיט, הופכה, עדיין פתוחה בסוף) וההערה שלכם. הורדת CSV מייצאת אותה לגיליון. עקומת ההון מציגה את החשבון מול קנה והחזק. Log מציג מה הסקריפט כתב עם log().

איך פקודות מתבצעות

  • בלי הצצה קדימה. פקודה שהוגשה ב-onBar(i) מתבצעת בפתיחת הנר הבא (i + 1). אסטרטגיה לעולם לא יכולה לסחור במחיר שלא יכלה לדעת.
  • סטופים בתוך הנר. סטופ לוס וטייק פרופיט נבדקים מול השיא והשפל של כל נר. אם שניהם יכלו להיפגע באותו נר, הסטופ נספר (ההנחה הזהירה). פער מעבר לסטופ מתבצע בפתיחה, כמו בשווקים אמיתיים.
  • פוזיציה אחת בכל פעם. long() בזמן שורט סוגר את השורט ופותח לונג ("הפיכה"); long() כשכבר בלונג רק מעדכן את הסטופים שמועברים.
  • עלויות בכל ביצוע. החלקה מזיזה כל מחיר ביצוע לרעתכם; עמלה נגבית בכניסה וביציאה.
  • הסוף. עסקה שעדיין פתוחה אחרי הנר האחרון נסגרת בסגירה האחרונה ומסומנת "עדיין פתוחה בסוף".
onBar(i): long() filled at this open candle i + 1

כתיבת אסטרטגיה משלכם

אסטרטגיה היא תוכנית JavaScript קצרה בשני חלקים:

  1. החלק העליון רץ פעם אחת: קראו את הפרמטרים עם input(), חשבו סדרות שלמות עם ta.* או ind(), ושרטטו אותן עם plot().
  2. function onBar(i) { … } רץ לכל נר, מהישן לחדש. i הוא מספר הנר (0 = הישן ביותר). כאן מחליטים: long(), short(), exit(), או כלום.
// 1. once: inputs and series
const len = input("Average length", 50, { min: 5, max: 400 });
const avg = ta.sma(close, len);           // one value per candle
plot(avg, "SMA " + len, "#2F80ED");       // drawn on the price chart

// 2. every candle
function onBar(i) {
  if (avg[i] == null) return;             // the first len - 1 values are null (warming up)
  if (position === 0 && close[i] > avg[i]) long();
  if (position > 0 && close[i] < avg[i]) exit("below the average");
}

דברים שכדאי לדעת מההתחלה:

  • סדרות הן מערכים, ערך אחד לכל נר, מהישן לחדש: close[i] הוא סגירת הנר הזה, close[i - 1] של הקודם. סדרות מחושבות הן null עד שיש מספיק נרות; בדקו לפני השימוש.
  • בתוך onBar(i) אפשר לקרוא נרות רק עד i. close[i + 1] עוצר את הבדיקה עם שגיאה: זו הייתה הצצה לעתיד.
  • השתמשו ב-const וב-let כרגיל; המשתנים שלכם שומרים על ערכיהם בין נרות (שימושי לסטופ נגרר).
  • המחירים ביחידות של הגרף (ל-EURUSD ‏1.0850, לזהב 2650.40); הזמן בשניות UTC.

אסמכתה

נרות והמצב הנוכחי

שםמה זה
open, high, low, close, volumeמערכים של ערכי הנרות, מהישן לחדש (הנפח הוא נפח טיקים).
timeזמן הפתיחה של כל נר בשניות UTC. new Date(time[i] * 1000).getUTCHours() נותן את השעה.
bars, symbol, timeframeמספר הנרות, הסימול (למשל "EURUSD") וטווח הזמן (למשל "H1").
positionבתוך onBar: ‏1 לונג, ‏-1 שורט, ‏0 ללא פוזיציה.
positionSize, entryPrice, entryBarגודל העסקה הפתוחה ביחידות, מחיר הביצוע ומספר הנר (null כשאין פוזיציה). i - entryBar = נרות שהוחזקו.
equity, cashשווי החשבון בסגירת הנר הזה (עם העסקה הפתוחה), והמזומן בלעדיה.

קלטים

קריאהתוצאה
input("Period", 14, { min: 2, max: 100, step: 1 })שדה מספרי (נשמר בין min ל-max). מחזיר את הערך שהוקלד, או 14.
input("Average", "EMA", { options: ["SMA", "EMA"] })רשימה. מחזירה את הטקסט שנבחר.

עד 30 פרמטרים. הערכים שלהם נשמרים עם האסטרטגיה ועוברים איתה כשמפרסמים אותה ברעיון.

חישובים (ta.*)

פונקציהמחזיר
ta.sma(src, n), ta.ema(src, n), ta.wma(src, n), ta.rma(src, n)ממוצע נע פשוט, אקספוננציאלי, משוקלל ושל ויילדר לכל סדרה.
ta.rsi(src, 14)RSI (0–100).
ta.atr(14), ta.tr()Average True Range (ממוצע פשוט, כמו בגרף) וה-True Range של כל נר.
ta.stdev(src, n)סטיית תקן על פני n נרות.
ta.highest(src, n), ta.lowest(src, n)הערך הגבוה / הנמוך ביותר של n הנרות האחרונים, כולל הנוכחי. לפריצה השוו ל-[i - 1].
ta.change(src, n = 1), ta.roc(src, n = 1)ההפרש לעומת לפני n נרות, וכן באחוזים.
ta.macd(src, 12, 26, 9){ macd, signal, hist }.
ta.bb(src, 20, 2)רצועות בולינגר { upper, middle, lower }.
ta.stoch(14, 3, 3)סטוכסטי { k, d } (תקופה, החלקת %D, האטה).
ta.supertrend(10, 3){ line, dir }: ‏dir שווה 1 במגמת עלייה ו--1 במגמת ירידה.

src הוא כל סדרה: close, high, תוצאה אחרת, או מערך משלכם. כל פונקציה מחזירה מערך חדש; שום דבר לא משנה את הנרות.

אותות

פונקציהנכון כאשר…
ta.crossover(a, b, i)a חוצה את b כלפי מעלה בנר i (בנר i - 1 הוא היה שווה לו או מתחתיו). b יכול להיות מספר: ta.crossover(rsi, 30, i).
ta.crossunder(a, b, i)a חוצה את b כלפי מטה.
ta.cross(a, b, i)כל אחד מהם.
ta.rising(s, n, i), ta.falling(s, n, i)s עלה (ירד) בכל אחד מ-n הנרות האחרונים.

פקודות

קריאההשפעה (בפתיחת הנר הבא)
long(options) (גם buy)פותח פוזיציית לונג; קודם סוגר שורט.
short(options) (גם sell)פותח פוזיציית שורט; קודם סוגר לונג. כשעסקאות שורט כבויות הוא רק סוגר את הלונג.
exit("reason")סוגר את הפוזיציה הפתוחה. הסיבה מופיעה ברשימת העסקאות.
stopLoss(price), takeProfit(price)מזיז מיד את הסטופ / היעד של העסקה הפתוחה (null מסיר אותו). השתמשו בהם לסטופים נגררים.
אפשרותמשמעות
{ sl: 1.0820, tp: 1.0950 }סטופ לוס וטייק פרופיט כמחירים.
{ slPct: 2, tpPct: 4 }סטופ ויעד באחוזים ממחיר הביצוע.
{ qty: 50000 }גודל ביחידות לפקודה הזו (במקום הגדרת גודל הפקודה).
{ comment: "breakout" }הערה שמוצגת עם העסקה.

פלט

קריאההשפעה
plot(series, "Name", "#2F80ED")משרטט קו על גרף המחיר (עד 12).
log("text", value, …)כותב שורה ללשונית Log עם זמן הנר (עד 200 שורות).

כל 71 האינדיקטורים של הגרף בקוד: ind()

ind(id, inputs) מחשב כל אינדיקטור של הגרף בדיוק כמו הגרף. הוא מחזיר את הקו הראשון שלו כסדרה; כל הקווים נמצאים ב-.lines והשמות שלהם ב-.names. פרמטרים שמשמיטים מקבלים את ברירת המחדל המוצגת. method הוא אחד מ-SMA, EMA, SMMA, LWMA; price אחד מ-close, open, high, low, median, typical, weighted.

const st = ind("stoch", { k: 14, d: 3, slowing: 3 });   // st = %K, st.lines[1] = %D
const ich = ind("ichimoku");                            // ich.names: Tenkan, Kijun, Span A, Span B, Chikou
const kijun = ich.lines[1];
idאינדיקטורפרמטרים (ברירת מחדל)קווים
maMoving Averageperiod: 20, method: SMA, price: close, shift: 0MA
amaAdaptive Moving Averageperiod: 9, fast: 2, slow: 30, price: closeAMA
adxAverage Directional Movement Indexperiod: 14ADX, +DI, −DI
adxwADX Wilderperiod: 14ADX, +DI, −DI
bbBollinger Bandsperiod: 20, dev: 2, price: close, shift: 0Middle, Upper, Lower
demaDouble Exponential Moving Averageperiod: 14, price: closeDEMA
envEnvelopesperiod: 14, method: SMA, dev: 0.1, price: closeUpper, Lower
framaFractal Adaptive Moving Averageperiod: 14, price: closeFrAMA
ichimokuIchimoku Kinko Hyotenkan: 9, kijun: 26, senkou: 52Tenkan, Kijun, Span A, Span B, Chikou
sarParabolic SARstep: 0.02, max: 0.2SAR
stddevStandard Deviationperiod: 20, method: SMA, price: closeStdDev
temaTriple Exponential Moving Averageperiod: 14, price: closeTEMA
vidyaVariable Index Dynamic Averagecmo: 9, ema: 12, price: closeVIDYA
atrAverage True Rangeperiod: 14ATR
bearsBears Powerperiod: 13Bears
bullsBulls Powerperiod: 13Bulls
cciCommodity Channel Indexperiod: 14, price: typicalCCI
chaikinChaikin Oscillatorfast: 3, slow: 10, method: EMACHO
demarkerDeMarkerperiod: 14DeMarker
forceForce Indexperiod: 13, method: SMAForce
macdMACDfast: 12, slow: 26, signal: 9, price: closeMACD, Signal
momentumMomentumperiod: 14, price: closeMomentum
osmaMoving Average of Oscillatorfast: 12, slow: 26, signal: 9, price: closeOsMA
rsiRelative Strength Indexperiod: 14, price: closeRSI
rviRelative Vigor Indexperiod: 10RVI, Signal
stochStochastic Oscillatork: 5, d: 3, slowing: 3, method: SMA%K, %D
trixTriple Exponential Averageperiod: 14, price: closeTRIX
wprWilliams' Percent Rangeperiod: 14%R
adAccumulation/DistributionאיןA/D
mfiMoney Flow Indexperiod: 14MFI
obvOn Balance VolumeאיןOBV
volumesVolumesאיןVolume
acAccelerator OscillatorאיןAC
alligatorAlligatorjaw: 13, jawShift: 8, teeth: 8, teethShift: 5, lips: 5, lipsShift: 3Jaw, Teeth, Lips
aoAwesome OscillatorאיןAO
fractalsFractalsאיןUp, Down
gatorGator Oscillatorjaw: 13, teeth: 8, lips: 5Upper, Lower
bwmfiMarket Facilitation IndexאיןBW MFI
zigzagZigZagdepth: 12, dev: 0.3ZigZag
vwapVWAP (volume-weighted average price)איןVWAP
supertrendSuperTrendperiod: 10, mult: 3Up trend, Down trend
keltnerKeltner Channelsperiod: 20, atr: 10, mult: 2Middle, Upper, Lower
donchianDonchian Channelsperiod: 20Upper, Lower, Middle
hmaHull Moving Averageperiod: 20, price: closeHMA
pivotsPivot Points (classic)איןP, R1, S1, R2, S2, R3, S3
stochrsiStochastic RSIrsi: 14, stoch: 14, k: 3, d: 3%K, %D
aroonAroonperiod: 25Aroon up, Aroon down
cmfChaikin Money Flowperiod: 20CMF
uoUltimate Oscillatorp1: 7, p2: 14, p3: 28UO
chopChoppiness Indexperiod: 14CHOP
vwmaVolume-Weighted Moving Averageperiod: 20VWMA
zlemaZero-Lag Exponential Moving Averageperiod: 21, price: closeZLEMA
almaArnaud Legoux Moving Averageperiod: 9, offset: 0.85, sigma: 6, price: closeALMA
mcginleyMcGinley Dynamicperiod: 14McGinley
lsmaLeast Squares Moving Averageperiod: 25, price: closeLSMA
chandelierChandelier Exitperiod: 22, mult: 3Long exit, Short exit
rocRate of Changeperiod: 12ROC
cmoChande Momentum Oscillatorperiod: 9CMO
tsiTrue Strength Indexlong: 25, short: 13, signal: 13TSI, Signal
ppoPercentage Price Oscillatorfast: 12, slow: 26, signal: 9Histogram, PPO, Signal
dpoDetrended Price Oscillatorperiod: 20DPO
kstKnow Sure Thingsignal: 9KST, Signal
vortexVortex Indicatorperiod: 14VI+, VI−
eomEase of Movementperiod: 14EOM
massMass Indexema: 9, sum: 25Mass Index
coppockCoppock Curvewma: 10, long: 14, short: 11Coppock
hvHistorical Volatilityperiod: 20HV %
fisherFisher Transformperiod: 9Fisher, Trigger
squeezeSqueeze Momentumbb: 20, bbk: 2, kc: 20, kck: 1.5Momentum, Squeeze on, Squeeze off
crsiConnors RSIrsi: 3, streak: 2, rank: 100CRSI
pvtPrice Volume TrendאיןPVT

דוגמאות

כל דוגמה רצה כמו שהיא: לחצו העתקה, פתחו את הקונסולה, בחרו סקריפט חדש…, הדביקו ולחצו הרצת בדיקה. התוצאות תלויות בסימול, בטווח הזמן ובתקופה; הדוגמאות מלמדות את הטכניקה, הן אינן המלצות.

1. Your first strategy: buy above a moving average

The smallest useful script. It is long while the close is above its 50-candle average and flat otherwise. The top of the script runs once; onBar(i) runs for every candle.

const len = input("Average length", 50, { min: 5, max: 400 });
const avg = ta.sma(close, len);
plot(avg, "SMA " + len, "#2F80ED");

function onBar(i) {
  if (avg[i] == null) return;                 // still warming up
  if (position === 0 && close[i] > avg[i]) long({ comment: "close above the average" });
  if (position > 0 && close[i] < avg[i]) exit("close below the average");
}

2. Moving average crossover, long and short

Always in the market: long() while short reverses the position (and short() while long). Untick Allow short trades in the settings to make it long-only without changing the code.

const fast = ta.ema(close, input("Fast EMA", 12, { min: 2, max: 200 }));
const slow = ta.ema(close, input("Slow EMA", 26, { min: 3, max: 400 }));
plot(fast, "Fast", "#2F80ED");
plot(slow, "Slow", "#E39B2D");

function onBar(i) {
  if (ta.crossover(fast, slow, i)) long();
  if (ta.crossunder(fast, slow, i)) short();
}

3. Fixed stop loss and take profit in percent

slPct and tpPct are measured from the fill price. The stop and the target are checked inside every candle with its high and low; if both could have been hit in one candle, the stop counts.

const r = ta.rsi(close, 14);
const sl = input("Stop loss %", 1.5, { min: 0.1, max: 20, step: 0.1 });
const tp = input("Take profit %", 3, { min: 0.1, max: 50, step: 0.1 });

function onBar(i) {
  if (position !== 0) return;                 // one trade at a time
  if (ta.crossover(r, 30, i)) long({ slPct: sl, tpPct: tp, comment: "RSI back above 30" });
  if (ta.crossunder(r, 70, i)) short({ slPct: sl, tpPct: tp, comment: "RSI back below 70" });
}

4. ATR stop and a 2:1 target in prices

sl and tp take prices. Here the stop sits 2 ATR from the close and the target twice as far (risk/reward 1:2). The fill is at the next open, so the real distance can differ slightly.

const a = ta.atr(14);
const hi = ta.highest(high, 20);
const mult = input("Stop (ATR multiple)", 2, { min: 0.5, max: 6, step: 0.5 });

function onBar(i) {
  if (i < 1 || a[i] == null || hi[i - 1] == null || position !== 0) return;
  if (close[i] > hi[i - 1]) {                  // a new 20-candle high
    const stop = close[i] - mult * a[i];
    const target = close[i] + 2 * mult * a[i];
    long({ sl: stop, tp: target, comment: "breakout, risk " + (mult * a[i]).toFixed(5) });
  }
}

5. A trailing stop that follows the price

stopLoss(price) moves the stop of the open trade. This one trails 3 ATR under the highest close since the entry and never moves down.

const a = ta.atr(14);
const fast = ta.ema(close, 20), slow = ta.ema(close, 50);
let stop = null;

function onBar(i) {
  if (a[i] == null || slow[i] == null) return;
  if (position === 0) {
    stop = null;
    if (ta.crossover(fast, slow, i)) long({ comment: "trend up" });
    return;
  }
  const candidate = close[i] - 3 * a[i];
  if (stop === null || candidate > stop) {     // only ever raise it
    stop = candidate;
    stopLoss(stop);
  }
}

6. Any chart indicator with ind(): ADX trend filter

ind(id, inputs) gives the first line of any of the chart's 71 indicators; the other lines are in .lines (their names in .names). Here: trade the MACD cross only when ADX says the market is trending.

const adx = ind("adx", { period: 14 });      // .lines[0] ADX, [1] +DI, [2] -DI
const plusDI = adx.lines[1], minusDI = adx.lines[2];
const m = ta.macd(close, 12, 26, 9);
const minAdx = input("Minimum ADX", 25, { min: 10, max: 50 });

function onBar(i) {
  if (adx[i] == null || adx[i] < minAdx) return;
  if (ta.crossover(m.macd, m.signal, i) && plusDI[i] > minusDI[i]) long();
  if (ta.crossunder(m.macd, m.signal, i) && minusDI[i] > plusDI[i]) short();
}

7. Mean reversion with Bollinger Bands

Buys a close under the lower band, sells a close over the upper band, and exits at the middle band. A classic for ranging markets; it suffers in strong trends.

const b = ta.bb(close, input("Period", 20, { min: 5, max: 200 }), input("Width", 2, { min: 0.5, max: 4, step: 0.1 }));
plot(b.upper, "Upper", "#8E44AD");
plot(b.lower, "Lower", "#8E44AD");

function onBar(i) {
  if (b.middle[i] == null) return;
  if (position === 0 && close[i] < b.lower[i]) long({ comment: "below the lower band" });
  else if (position === 0 && close[i] > b.upper[i]) short({ comment: "above the upper band" });
  else if (position > 0 && close[i] >= b.middle[i]) exit("middle band");
  else if (position < 0 && close[i] <= b.middle[i]) exit("middle band");
}

8. Trade only at certain hours (time filter)

time[i] is the candle's open in UTC seconds. This example only opens trades between 07:00 and 16:00 UTC (the London session) and closes anything still open at 20:00. Use it on an intraday timeframe.

const from = input("Start hour (UTC)", 7, { min: 0, max: 23 });
const to = input("End hour (UTC)", 16, { min: 1, max: 24 });
const fast = ta.sma(close, 10), slow = ta.sma(close, 30);

function onBar(i) {
  const hour = new Date(time[i] * 1000).getUTCHours();
  if (position !== 0 && hour >= 20) { exit("end of the day"); return; }
  if (hour < from || hour >= to) return;
  if (ta.crossover(fast, slow, i)) long();
  if (ta.crossunder(fast, slow, i)) short();
}

9. Your own calculation: a volatility breakout

Series are plain arrays, so you can compute your own. This builds yesterday's range for every candle and buys a break above the open plus half of it. log() writes to the Log tab.

const k = input("Range multiple", 0.5, { min: 0.1, max: 2, step: 0.1 });
const range = high.map((h, i) => (i ? high[i - 1] - low[i - 1] : null));   // the previous candle's range
const trigger = open.map((o, i) => (range[i] == null ? null : o + k * range[i]));
plot(trigger, "Trigger", "#16A085");

function onBar(i) {
  if (trigger[i] == null) return;
  if (position === 0 && close[i] > trigger[i]) {
    long({ slPct: 1, comment: "close above open + " + k + " x range" });
    log("signal at", close[i], "trigger", trigger[i]);
  } else if (position > 0 && i - entryBar >= 3) {
    exit("held 3 candles");
  }
}

10. Position size from risk (1% of equity per trade)

{ qty } sets the size in units for one order, overriding the Order size setting. Here the size is chosen so that hitting the stop loses about 1% of the current equity.

const a = ta.atr(14);
const riskPct = input("Risk per trade %", 1, { min: 0.1, max: 5, step: 0.1 });
const fast = ta.ema(close, 20), slow = ta.ema(close, 50);

function onBar(i) {
  if (a[i] == null || slow[i] == null || position !== 0) return;
  if (ta.crossover(fast, slow, i)) {
    const stopDistance = 2 * a[i];
    const qty = (equity * riskPct / 100) / stopDistance;
    long({ qty: qty, sl: close[i] - stopDistance, tp: close[i] + 3 * stopDistance,
           comment: "risk " + riskPct + "%" });
  }
}

11. Two conditions in a row: pullback in an uptrend

Combines a trend filter (price above the 200 average), a pullback (RSI under 40 within the last 5 candles) and a trigger (close back above the 20 average).

const trend = ta.sma(close, 200), fast = ta.ema(close, 20), r = ta.rsi(close, 14);

function onBar(i) {
  if (trend[i] == null || i < 5) return;
  let dipped = false;
  for (let k = 0; k < 5; k++) if (r[i - k] != null && r[i - k] < 40) dipped = true;
  if (position === 0 && close[i] > trend[i] && dipped && ta.crossover(close, fast, i)) {
    long({ slPct: 2, tpPct: 4, comment: "pullback bought" });
  }
}

שגיאות ואיך לתקן אותן

הודעהסיבה ותיקון
the script needs a function onBar(i) { … }לסקריפט אין onBar, או שהוא מאוית שגוי (onbar). כתבו function onBar(i) { … } ברמה העליונה של הסקריפט, לא בתוך פונקציה אחרת.
close[124] is in the future: inside onBar(123) only candles up to 123 are knownקראתם נר מאוחר יותר. השתמשו ב-close[i] ובקודמים (close[i - 1]). לפריצה, השוו את סגירת היום לשיא הגבוה של אתמול: close[i] > hi[i - 1].
close cannot be changedהנרות לקריאה בלבד. צרו במקום זאת מערך משלכם: const mid = close.map((c, i) => (c + open[i]) / 2);
Cannot read properties of null / ‏NaN בתוצאותסדרה עדיין null בהתחלה (חימום). התחילו את onBar עם if (avg[i] == null) return;, ובדקו i >= 1 לפני השימוש ב-[i - 1].
unknown indicator "…"השתמשו במזהה מטבלת האינדיקטורים (באותיות קטנות), למשל ind("adx"), לא ind("ADX").
אין עסקאות: האסטרטגיה מעולם לא שלחה פקודההתנאים אף פעם לא התקיימו יחד. הוסיפו log("rsi", r[i]) כדי לראות את הערכים, הקלו תנאי, או טענו עוד נרות.
האסטרטגיה לקחה יותר מ-15 שניות (לולאה אינסופית?)לולאה שלא נגמרת, או לולאה כבדה בתוך onBar. חשבו סדרות פעם אחת בחלק העליון במקום לעבור על כל הנרות בכל נר.
Unexpected token / SyntaxError (שורה N)טעות הקלדה בשורה הזו: סוגר, מירכאה או פסיק חסרים.

בדיקות שאפשר לסמוך עליהן

  • הוסיפו את העלויות. אסטרטגיה שסוחרת הרבה יכולה להיראות מצוין בלי עלויות ולהפסיד כסף עם מרווח מציאותי. מלאו תמיד החלקה (המרווח) ועמלה.
  • השתמשו במספיק עסקאות. מתחת לכ-30 עסקאות, המספרים הם בעיקר מקרה. טענו עוד נרות או השתמשו בטווח זמן קצר יותר.
  • אל תתאימו לעבר. ניסוי פרמטרים רבים עד שהתוצאה מושלמת מוצא את הרעש של התקופה, לא כלל שעובד. כווננו על חלק מההיסטוריה, ואז בדקו את אותם פרמטרים בתקופה אחרת ובכמה סימולים אחרים.
  • השוו לקנה והחזק והסתכלו על הירידה מהשיא, לא רק על הרווח.
  • שימו לב לקיצוניים. אם עסקה או שתיים מייצרות את כל הרווח, האסטרטגיה תלויה במזל.
  • תרגלו לפני שאתם מסכנים כסף. הריצו את האסטרטגיה קדימה במסחר מדומה או בהפעלת נרות חוזרת, והגדירו התראות לאותות שלה.

בדיקות לאחור משתמשות בנרות bid מהעבר ומתעלמות מסוואפים, מימון ומרווחים שמשתנים עם השוק. ביצועי עבר אינם מבטיחים תוצאות עתידיות. זה אינו ייעוץ השקעות.

שמירה, שיתוף, פרסום

  • שמירה (כשאתם מחוברים) שומרת עד 50 אסטרטגיות עם הפרמטרים וההגדרות שלהן; הן מופיעות ברשימה בכל גרף.
  • פרסמו רעיון מהגרף וצרפו אסטרטגיה: הקוראים יכולים לפתוח את הגרף שלכם ולהריץ את האסטרטגיה בעצמם, עם הפרמטרים שלכם. ראו רעיונות.
  • שתפו את הניתוח שלכם עם צוות במועדון.
  • הורדת CSV בלשונית העסקאות מייצאת את העסקאות לגיליון.
  • למחקר כבד יותר, משכו את אותם נרות דרך API המחירים (GET /bars) ל-Python, ‏R או Excel.

מגבלות

נרות לבדיקהמבקרים: הנרות שעל הגרף. מחוברים: עד 20,000 (תוכניות Premium יכולות להעלות זאת; ראו Premium).
סקריפט50,000 תווים, 30 פרמטרים, 12 קווים משורטטים, 200 שורות יומן, 5,000 עסקאות ברשימה, 15 שניות ריצה.
אסטרטגיות שמורות50 לחשבון.
פוזיציותפוזיציה אחת בכל פעם לבדיקה (לונג, שורט או ללא); סימול אחד וטווח זמן אחד לבדיקה.

שאלות

האם צריך לדעת לתכנת?

לא. האסטרטגיות המובנות עובדות בלי קוד; משנים רק את הפרמטרים שלהן. כשרוצים יותר, עריכת עותק נותנת סקריפט עובד לשנות שורה אחר שורה, והדוגמאות למעלה מכסות את אבני הבניין הרגילות.

האם זה כמו Pine Script?

הרעיון זהה (סדרות, פרמטרים, קווים, פקודות), השפה היא JavaScript רגיל. רוב אסטרטגיות Pine הפשוטות מתורגמות שורה אחר שורה: ta.sma(close, 20) נשאר ta.sma(close, 20), ‏strategy.entry("L", strategy.long) הופך ל-long(), וגוף הסקריפט נכנס ל-onBar(i) עם [i] אחרי כל סדרה.

האם האסטרטגיה יכולה לסחור בשבילי?

לא. הקונסולה בודקת רק על נרות עבר. כדי לעקוב אחרי אסטרטגיה בזמן אמת, השתמשו במסחר מדומה ובהתראות, או קראו לAPI המחירים מתוכנה משלכם.

למה התוצאה שלי שונה מזו של פלטפורמה אחרת?

נרות שונים (bid לעומת מחירי אמצע, שעות המושב של הברוקר), ביצוע בפתיחה הבאה במקום בסגירה, עלויות וכלל הסטופ-לפני-היעד משנים כולם את התוצאות. השוו דומה לדומה.

האם הקוד שלי פרטי?

כן. הוא רץ בדפדפן שלכם; הוא נשמר בחשבון רק כשלוחצים שמירה, ואחרים רואים אותו רק אם תפרסמו אותו ברעיון.