دليل · مختبر الاستراتيجيات

وحدة الاختبار الرجعي: اختبر استراتيجيات التداول بالكود

لكل رسم بياني زر الاستراتيجية. يفتح وحدة تعيد تشغيل استراتيجية على الشموع السابقة وتعرض كل صفقة على الرسم والربح والتراجع ونسبة الربح ومنحنى رأس المال مقارنةً بالشراء والاحتفاظ. ابدأ باستراتيجية مدمجة، ثم اكتب استراتيجيتك في بضعة أسطر من 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()متوسط المدى الحقيقي (متوسط بسيط كما على الرسم) والمدى الحقيقي لكل شمعة.
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 مقابل المتوسطة، وأوقات جلسات الوسيط)، والتنفيذ عند الافتتاح التالي بدل الإغلاق، والتكاليف، وقاعدة الوقف قبل الهدف، كلها تغيّر النتائج. قارن المتماثل بالمتماثل.

هل الكود الخاص بي خاص؟

نعم. يعمل في متصفحك؛ ولا يُخزَّن في حسابك إلا عند الضغط على حفظ، ولا يراه الآخرون إلا إذا نشرته في فكرة.