حزمة شفرة المتداول — Python وPine Script
ستة مقاطع للنسخ: أربعة بلغة Python لتحميل دفتر CSV والمؤشرات ومنحنى رأس المال مع التراجع وحساب حجم المركز بـATR، واثنان بلغة Pine Script للنطاق اليومي نسبةً إلىATR مع تنبيه ولنوافذ جلسات الخطة على الرسم. كلها أدوات تحليل؛ تحسب وترسم وتذكّرك، ولا يولّد أي مقطع إشارات شراء/بيع أو يتخذ قرارات، فذلك عمل دليل الأنماط. تبقى المعرّفات وأسماء واجهات API بالإنجليزية بما يتسق مع توثيق pandas وPine Script ورسائل الخطأ؛ أما التعليقات وتسميات المخرجات الموجّهة للقارئ فتُقدّم بالعربية في هذه النسخة. وتحافظ ورشة الذكاء الاصطناعي على اصطلاح الأسماء التقنية في موجّهات الشفرة؛ والشروح المحيطة بلغة الدورة وتقودك خطوة بخطوة. البيئة: تثبيت Python والتشغيل الأول مشروحان في 11.8؛ وعناوين أعمدة الدفتر في الملحق F.
- أدوات، وليست استراتيجيات: تحسب الشفرة المؤشرات من بياناتك وتتابع خطتك؛ والحد الفاصل هو نفسه في قسم «ما لا يفعله الذكاء الاصطناعي» من الملحق H وللأسباب نفسها
- تنسيق بيانات مشترك: تقرأ مقاطع Python عناوين جدول الدفتر، الملحق F؛ ويشمل مقام معدل الفوز صفقات التعادل، وتستخدم القيمة المتوقعة النتيجة الصافية. هي التعريفات نفسها في الموجّه P5
- Pine Script دون استشراف بيانات مستقبلية: يجلب S5 بيانات يومية باستخدام
lookahead=barmerge.lookahead_off؛ ولا يصل S6 إلى إطار أعلى أصلًا، ويستخدم الدالةtimeفقط. غياب الاستشراف لا يثبت غياب إعادة الرسم؛ ويشرح وصف S5 ما تراه في الأعمدة التاريخية والوقت الفعلي. هذه المزالق مما تبحث عنه مراجعة الشفرة بالموجّه P3 - تقرّب حاسبة الحجم إلى أسفل: عند تحويل المخاطرة إلى لوت، يرفع التقريب إلى أعلى المخاطرة منهجيًا فوق الخطة؛ وهذا السطر الواحد هو الفرق بين1% و«نحو1%»
قبل تشغيل الشفرة: ثلاث قواعد
- اقرأ قبل التشغيل. كل مقطع قصير عمدًا؛ ينبغي أن تفهم كل سطر. عدّل الشفرة التي لا تفهمها بمراجعة P3، لا بالتخمين؛ وتنطبق القاعدة مضاعفة على مقاطع المنتديات والمحادثات.
- تدخل البيانات من الملفات؛ ولا تخرج القرارات من الشفرة. تقرأ البرامج تصدير دفتر بتنسيق الملحق F ومعلمات تقدمها صراحة. المخرجات أرقام ورسوم للمراجعة الأسبوعية؛ وأنت تستخلص النتائج باتباع تدقيق15.10 ومراعاة حجم العينة والاعتماد بين الصفقات وعدم اليقين في النتيجة.
- البيئة من11.8: Python 3.11 أو أحدث، مع
pandasوmatplotlibويُشرح التثبيت والبرنامج الأول هناك. أُعيد تشغيل المقاطع S1–S4 في17 سبتمبر2026 باستخدام Python 3.12.10 وpandas 3.0.5 وmatplotlib 3.11.1. لم تُختبر إصدارات أخرى. الصق Pine Script في محرر مؤشرات منصة الرسم؛ يستخدم المؤشران الإصدار6.
الخطوات الدنيا للتشغيل: في بيئة Python 3.11+، افحص الإصدار باستخدام python --version، ثم ثبّت الحزم باستخدام python -m pip install pandas==3.0.5 matplotlib==3.11.1، واحفظ S1+S2+S3 باسم analiza_dziennika.py وملف CSV للاختبار باسم dziennik.csv، ثم شغّل python analiza_dziennika.py. يحتاج S4 المكتبة القياسية فقط. الصق S5 وS6 في Pine Editor كلًا على حدة. جرى فحص مقطعي Pine مقابل توثيق v6، ولم تُجرَ ترجمتهما برمجيًا أو اختبار تنبيهاتهما في TradingView.
S1 · تحميل دفتر CSV
Python 3 · pandasنقطة البداية لـS2 وS3: يقرأ تصدير جدول الملحق F، ويفحص العناوين وعدد الحقول، ثم ينظف العمود r_net . توقف أسماء الأعمدة المكررة أو عنوان فارغ أو حقول أكثر أو أقل الاستيراد؛ ولا يختار البرنامج بين عمودَي نتائج أو ينقل البيانات إلى الفهرس. مثّل الحقل الفارغ بفاصل، مثل ;A+;;0؛ فالصف المبتور حالة مختلفة. اضبط الفاصل والرمز العشري لنسخة CSV؛ PL بفاصلة منقوطة وفاصلة عشرية، وEN بفاصلة ونقطة، مع الترميز: تستخدم ملفات مولّد الملحق F ترميز UTF-8، ويمكن قراءة “CSV UTF-8” المحفوظ في Excel بترميز UTF-8 أيضًا؛ وقد يحتاج تصدير أقدم بصفحة الترميز البولندية cp1250. افحص تنسيق الحفظ، فلغة الواجهة لا تحدد الترميز وحدها. إذا كان r_net فارغًا و close_time_utc فارغًا، فالصفقة لم تغلق بعد وتُتجاوز؛ أما وقت إغلاق بلا نتيجة فيعني سجلًا ناقصًا ويوقف الحساب. توقف البرنامج قيمة غير فارغة لا تُقرأ كرقم، بما فيها “NA” أو شرطة، مع الإبلاغ عن رقم السجل؛ وكذلك صفقة مغلقة بلا وقت إغلاق بتنسيق الملحق F، أي2026-07-08 13:15، وإلا لوجب تخمين ترتيب المنحنى.
import pandas as pd
CSV_PATH = "dziennik.csv" # ملف مُصدّر من اليوميات (بنية الملحق F)
CSV_SEP = ";" # ";" لملف CSV بالإعدادات المحلية البولندية، و"," للإنجليزية
DECIMAL = "," # "," لملف CSV بالإعدادات المحلية البولندية، و"." للإنجليزية
ENCODING = "utf-8-sig" # يكتب مولّد الملحق F ترميز UTF-8 (مع معالجة BOM)؛ وقد يتطلب CSV القديم بصفحة الرموز البولندية "cp1250"
REQUIRED = ["r_net", "setup", "setup_class", "error_code", "close_time_utc"]
# اقرأ ملفًا محليًا وتحقّق من بنيته قبل إنشاء DataFrame.
# قد يعيد pandas.read_csv تسمية العناوين المكررة أو يستنتج فهرسًا من الحقول الزائدة.
import csv
try:
with open(CSV_PATH, encoding=ENCODING, newline="") as source:
reader = csv.reader(source, delimiter=CSV_SEP, strict=True)
header = next(reader, None)
if not header:
raise SystemExit("تعذّرت قراءة CSV: صف العناوين فارغ.")
if any(not name or name != name.strip() for name in header):
raise SystemExit("اسم عمود فارغ أو تحيط به مسافات — أصلح عنوان CSV.")
duplicates = sorted({name for name in header if header.count(name) > 1})
if duplicates:
raise SystemExit(f"أعمدة مكررة: {duplicates} — عالجها في اليوميات.")
rows, record_indexes = [], []
for index, row in enumerate(reader):
if not row: # سجل CSV فارغ بالكامل
continue
if len(row) != len(header):
raise SystemExit(f"السجل {index + 1}: العدد المتوقع للحقول {len(header)}، والعدد الفعلي {len(row)} "
f"— تحقّق من الفواصل وعلامات الاقتباس؛ لم يُحذف أي حقل.")
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"تعذّر فك ترميز {CSV_PATH} باستخدام {ENCODING} — تحقّق من UTF-8 أو الترميز القديم cp1250.") from None
except (OSError, csv.Error) as exc:
raise SystemExit(f"تعذّرت قراءة {CSV_PATH}: {exc}") from None
missing = [c for c in REQUIRED if c not in df.columns]
if missing:
raise SystemExit(f"أعمدة مفقودة: {missing} — طابق العناوين مع الملحق F والإعداد CSV_SEP.")
raw = df["r_net"] # يُسمح بنتيجة فارغة فقط عندما يكون وقت الإغلاق فارغًا أيضًا
txt = raw.astype("string").str.strip().str.replace(DECIMAL, ".", regex=False) # حلّل العمود مباشرةً: يجب ألا تخفي خلية غير صالحة الخلايا القابلة للقراءة
r = pd.to_numeric(txt, errors="coerce").astype("Float64") # تجنّب التفاف الأعداد الصحيحة في عمليات الجمع اللاحقة
r = r.where(r.abs() != float("inf")) # القيمة inf ليست مضاعف R صالحًا أيضًا
invalid = raw.notna() & r.isna() # الخلية مُعبّأة ولكن قيمتها غير قابلة للقراءة كعدد
if invalid.any():
raise SystemExit(f"قيمة r_net غير صالحة في السجلات {(df.index[invalid] + 1).tolist()} "
f"(السجل 1 = أول صف تحت العناوين) — تحقّق من القيم والإعداد DECIMAL؛ "
f"القيم NA والشرطات واللانهاية ليست أعدادًا.")
blank = df.isna().all(axis=1) # صف فارغ بالكامل = صف غير مستخدم في الورقة (تصدير XLSX للورقة كاملة)، وليس صفقة
df, r = df[~blank], r[~blank]
has_close = df["close_time_utc"].fillna("").str.strip().ne("")
incomplete = r.isna() & has_close
if incomplete.any():
raise SystemExit(f"قيمة r_net مفقودة للسجلات المغلقة {(df.index[incomplete] + 1).tolist()} "
f"— أكمل صافي النتيجة قبل حساب المؤشرات.")
open_trades = int(r.isna().sum())
df = df.assign(r_net=r).dropna(subset=["r_net"]) # الاحتفاظ بالفهرس = أرقام السجلات المستخدمة في الرسالة أدناه
# يتطلب منحنى رأس المال والتراجع ترتيبًا زمنيًا (الملحق F: حسب وقت الإغلاق) — الصفقة المغلقة دون وقت إغلاق قابل للقراءة توقف البرنامج
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) # يكتب الملحق F التاريخ 2026-07-08 13:15؛ التنسيق الثابت يجعل الفحص مستقلًا عن ترتيب الصفوف، ويمنع utc=True اللاحقة العارضة "Z"/"+00:00" من تعطيله
if closed.isna().any():
raise SystemExit(f"قيمة close_time_utc غير قابلة للقراءة في السجلات {(df.index[closed.isna()] + 1).tolist()} "
f"— تحتاج كل صفقة مغلقة إلى وقت إغلاق بتنسيق الملحق F (2026-07-08 13:15)؛ أصلح اليوميات، لا البرنامج.")
df = df.assign(_t=closed).sort_values("_t", kind="stable").drop(columns="_t").reset_index(drop=True)
print(f"تم تحميل {len(df)} صفقة مغلقة ({open_trades} صف/صفوف تم تجاوزها: لا وقت إغلاق ولا r_net).")
تحصل علىDataFrame، وهو df، جاهز للمقاطع التالية ومرتب بوقت الإغلاق، وبهذا الترتيب يُحسب المنحنى والتراجع، مع عدد الصفقات المفتوحة المتجاوزة. الصف الفارغ سجل فارغ كليًا، كما في تصدير ورقة XLSX كاملة، ولا يعده البرنامج؛ والصف الذي يحوي بيانات بلا نتيجة أو وقت إغلاق يُتجاوز كصفقة لم تغلق بعد؛ أما السجل المغلق بلا نتيجة فيوقف البرنامج. إذا توقف بقائمة سجلات، فأصلح الصفوف المحددة في الدفتر لا البرنامج؛ وإذا تأثر العمود كله، فافحص أيضًا DECIMAL الثابت. يبدأ ترقيم السجلات بعد العنوان ويشمل السجلات الفارغة؛ وقد يحوي الحقل المقتبس فاصلًا أو سطرًا جديدًا ويبقى سجلًا واحدًا. يجب أن تظهر كل صفقة مرة؛ افحص معرّفات trade_id قبل دمج الصادرات، فلا يزيل S1 تكرارات السجل. لا يكفي تاريخ بلا وقت لإعادة بناء التسلسل. يُعامل وقت بلا علامة منطقة زمنية كـUTC؛ ويُحوّل فرق ISO 8601 الصريح إلىUTC. عند تساوي الأوقات يحفظ البرنامج ترتيب السجلات؛ حدّده في الدفتر لأنه يؤثر في مسار التراجع.
S2 · مؤشرات الدفتر
Python 3 · pandasالتعريفات نفسها في الموجّه P5 ولوحة الجدول؛ يشمل مقام معدل الفوز صفقات التعادل؛ ويعيد معامل الربح رسالة بدل القسمة على الصفر؛ والقيمة المتوقعة متوسط صافي R (r_net؛ ويُقاس التراجع من المنحنى التراكمي بدءًا من0 R، فالخسارة الأولى تراجع بالفعل، كما في صيغة الجدول F. شغّله بعد S1. تعريفات المؤشرات مشتركة، لكن سياسة الأخطاء تختلف عن P5: يوقف S1 التحليل إذا كانت نتيجة صفقة مغلقة غير صالحة، بينما يوجّه P5 لتجاوز الصف وعدّه. لا تقارن النتائج قبل تحديد الصفقات التي دخلت العينتين.
import math
def metrics(r):
"المؤشرات الأساسية لليوميات على سلسلة من مضاعفات R الصافية.\n التعريفات (كما في لوحة الملحق F):\n - نسبة الربح: الصفقات ذات r > 0 مقسومة على جميع الصفقات الصالحة (تبقى الصفقات المتعادلة في المقام)\n - معامل الربح: مجموع r الموجبة مقسومًا على abs لمجموع r السالبة\n - القيمة المتوقعة: المتوسط الحسابي لقيم r (بعد التكاليف)\n - أقصى تراجع: أكبر هبوط لمنحنى R التراكمي عن قمته المتحركة،\n ويبدأ المنحنى عند 0 R (لذلك فإن خسارة أولى بمقدار -1 R تمثل بالفعل تراجعًا بمقدار 1 R)"
n = len(r)
if n == 0:
raise SystemExit("لا توجد صفقات صالحة — لا شيء لقياسه.")
try:
r = r.astype(float)
except (TypeError, ValueError):
raise SystemExit("تتطلب المؤشرات قيم R صافية رقمية — شغّل S1 أولًا.") from None
if not r.map(math.isfinite).all():
raise SystemExit("تتطلب المؤشرات قيم R صافية منتهية — شغّل S1 أولًا.")
wins = r[r > 0]
losses = r[r < 0]
equity = r.cumsum()
peak = equity.cummax().clip(lower=0) # الملحق F: MAX(0; القمة المتحركة)
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("تم تجاوز النطاق العددي — تحقّق من قيم R؛ لم تُرجع أي مؤشرات.") 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("تم تجاوز النطاق العددي — تحقّق من قيم R؛ لم تُرجع أي مؤشرات.")
pf = "لا خسائر في العينة" 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}")
تحصل على ستة مؤشرات للمراجعة الأسبوعية؛ إذا لم توجد خسائر يكون PF رسالة لا رقمًا. إذا تجاوزت القيم نطاق الحساب، يوقف البرنامج التحليل بدل إرجاع inf, NaN أو تراجع يبدو صفريًا. WR = 0.4 يعني40%. يُحسب PF بوحدات R، لاPLN؛ ومع تغير المخاطرة النقدية قد تختلف النتائج. التكاليف مشمولة بالفعل في r_net ؛ فلا يطرحها S2 مجددًا. لا تتوقع تقييم أفضليتك من المتوسط وحده أو مجرد تجاوز20 أو50 صفقة. تعريفات اللوحة في الملحق F، وخطة اختيار العينة والتكاليف والتحقق في الملحق N.
S3 · منحنى رأس المال والتراجع
Python 3 · pandas + matplotlibيرسم منحنى R التراكمي والتراجع من القمة أسفله، ويحفظ PNG بجانب ملف CSV المحدد بـ CSV_PATH في S1، بصرف النظر عن مجلد تشغيل البرنامج. يكشف المنحنى تسلسل النتائج وتكتلات الخسائر التي تختفي في الأرقام الإجمالية. هو مجموع R، لا رصيد الحساب بـPLN أو نسبة صافي قيمته؛ ومع تغير المخاطرة النقدية لا يعيد إنتاج تغيرات الرصيد. لا يشمل الرسم الإيداعات أو السحوبات أو نتائج المراكز المفتوحة. شغّله بعد S1.
import math
import matplotlib.pyplot as plt
from pathlib import Path
if len(df) == 0:
raise SystemExit("لا توجد صفقات مغلقة — لا شيء لرسمه.")
equity = df["r_net"].astype(float).cumsum()
drawdown = equity.cummax().clip(lower=0) - equity # التعريف نفسه في S2 والملحق F (يبدأ المنحنى عند 0 R)
if not equity.map(math.isfinite).all() or not drawdown.map(math.isfinite).all():
raise SystemExit("تم تجاوز النطاق العددي — تحقّق من قيم R؛ لم يُحفظ أي رسم.")
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 6), sharex=True,
gridspec_kw={"height_ratios": [3, 1]})
x = [0, *(equity.index + 1)] # الصفقة 0 = نقطة البداية 0 R التي يُقاس منها التراجع
ax1.plot(x, [0.0, *equity.values])
ax1.set_ylabel("رأس المال (R)")
ax1.set_title("منحنى رأس المال — صافي R التراكمي")
ax1.grid(True, alpha=0.3)
ax2.fill_between(x, [0.0, *(-drawdown.values)], 0, alpha=0.5)
ax2.set_ylabel("التراجع (R)")
ax2.set_xlabel("رقم الصفقة")
ax2.grid(True, alpha=0.3)
fig.tight_layout()
PNG_PATH = Path(CSV_PATH).with_name("equity_curve.png") # بجوار ملف اليوميات، أيًا كان دليل العمل
fig.savefig(PNG_PATH, dpi=150)
plt.close(fig)
print(f"تم الحفظ: {PNG_PATH}")
تحصل على ملف equity_curve.png بجانب الدفتر؛ يبدأ المنحنى من0 R، أي الصفقة0، ومنه يُقاس التراجع. تُظهر اللوحة السفلى تراجع R التراكمية من قمتها، بدءًا من0 R كما في S2 والجدول F، عبر التاريخ كله؛ وليس خسارة أسبوع. افحص حد الخطة الأسبوعي، الملحق E، منفصلًا أسبوعًا بأسبوع بالوحدة وقاعدة إعادة الضبط المحددتين في الخطة.
احفظ باسم dziennik.csv بترميز UTF-8 بجانب البرنامج المدمج S1+S2+S3 وشغّله. يتضمن الملف الأعمدة التي يحتاجها S1 فقط؛ ويُحمّل تصدير الملحق F الكامل،26 عمودًا، بالطريقة نفسها. الصف الأخير صفقة مفتوحة ذات r_net فارغ؛ والصفقتان المغلقتان الأوليان خاسرتان، لذا يُقاس التراجع من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;;
المخرجات المتوقعة: Python 3.12.10 وpandas 3.0.5 وmatplotlib 3.11.1؛ شُغّلت في17 سبتمبر2026:
تم تحميل 5 صفقات مغلقة (1 صف/صفوف تم تجاوزها: لا وقت إغلاق ولا 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
تم الحفظ: equity_curve.png
حساب للفحص اليدوي: أرباح1.83 +2.40 = 4.23 R، وخسائر1.00 +1.08 = 2.08 R → PF 2.03؛ والمجموع2.15 R /5 = 0.43 R؛ والمنحنى−1.00 → −2.08 → −0.25 → −0.25 → 2.15، مع قمة بداية0 R → تراجع2.08 R. دون نقطة0 R كان سيصبح1.08 R؛ وهذا الفرق وراء تعريف الملحق F. تخص المخرجات هذا الملف بالضبط والإصدارات المذكورة؛ وإذا اختلفت، فافحص البيانات، أي الفاصل والرمز العشري والترميز وترتيب الصفوف، ثم ثوابت S1، فالشفرة، فإصدارات الحزم، بهذا الترتيب.
S4 · حساب حجم المركز بـATR
Python 3 · المكتبة القياسيةالحجم باللوت لمسافة وقف k × ATR: يأتي مبلغ المخاطرة من رأس المال والنسبة، والمسافة منATR، ويُقرّب الحجم إلى أسفل وفق خطوة اللوت لحسابك، بالمعلمتين lot_step و min_lot وقيمتهما الافتراضية0.01، كي لا تتجاوز المخاطرة المخططة الميزانية. قد تزيد الخسارة الفعلية؛ يستبعد الحساب الانزلاق والفجوات عبر الوقف والفارق والعمولة والمبادلة. يجب أن يكون رأس المال وقيمة النقطة بعملة الحساب نفسها؛ وافحص منفصلًا الحد الأقصى للحجم ومتطلبات الهامش بالمواصفات. أدخل ATR بالنقاط؛ EURUSD 0.0080 → 80 وUSDJPY 0.80 → 80. يشرح حجم النقطة ملف الزوج، الملحق B؛ وقيمة النقطة لكل1 لوت في مواصفات الأداة، أو احسبها بحاسبة الملحق 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):
"الحجم باللوت لوقف يساوي atr_mult × ATR.\n atr_pips: قيمة ATR بالنقاط PIPS، وليس بوحدات السعر (EURUSD ATR 0.0080 -> 80؛ USDJPY ATR 0.80 -> 80 — حجم النقطة للزوج).\n pip_value_per_lot: قيمة 1 نقطة لكل 1.00 لوت، بعملة الحساب\n (مثلًا ~10 USD لزوج EURUSD في حساب USD — تحقّق من مواصفات الأداة).\n lot_step / min_lot: خطوة الحجم والحد الأدنى لحسابك (0.01 شائع وليس عامًا).\n يُقرّب إلى الأسفل إلى مضاعفات lot_step، مقاسةً من الصفر. حساب الكسور Fraction\n يحافظ على المدخلات العشرية دون الاعتماد على دقة Decimal العامة.\n المخاطرة المخطّطة ليست أقصى خسارة: الانزلاق والفجوات والسبريد والمبادلة غير مشمولة في هذا النموذج."
inputs = (capital, risk_pct, atr_pips, atr_mult, pip_value_per_lot, lot_step, min_lot)
if any(isinstance(x, bool) or not isinstance(x, (int, float, Decimal)) for x in inputs):
raise ValueError("استخدم قيمًا رقمية، لا نصوصًا أو قيمًا منطقية (الأعداد العشرية في Python تستخدم نقطة).")
decimals = tuple(Decimal(str(x)) for x in inputs)
if not all(x.is_finite() and x > 0 for x in decimals):
raise ValueError("يجب أن تكون كل المدخلات أعدادًا موجبة ومنتهية.")
c, p, a, k, v, step, minimum = map(Fraction, decimals)
if p > 100:
raise ValueError("risk_pct نسبة مئوية من رأس المال (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": "لا يوجد حجم مقبول لهذه القيم من lot_step وmin_lot ضمن ميزانية المخاطرة."}
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("تتجاوز المدخلات النطاق العددي للمخرجات.") from None
if not all(math.isfinite(value) and value > 0 for value in result.values()):
raise ValueError("تتجاوز المدخلات النطاق العددي للمخرجات.")
return result # أعداد عشرية عائمة للعرض؛ دون تقريب إضافي للوقف أو القيم النقدية
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}
تحصل على لوت مقرب إلى أسفل للخطوة ومبلغ المخاطرة المخطط الناتج؛ في النموذج دون تكاليف يكون≤ الميزانية، وقد تزيد الخسارة الفعلية. تُقاس الخطوة من الصفر؛ فتأكد من أن حسابك يستخدم شبكة الأحجام هذه. لا يُقرّب الوقف والمبالغ النقدية أكثر؛ مثلًاATR بمقدار0.26 نقطة ×1.25 يعطي0.325 نقطة، لا0.3. تُعاد المخرجات كقيم float للقراءة، بينما يُحسب عدد خطوات اللوت بكسور دقيقة؛ ولا يزال الحد الأدنى لتحرك سعر الأداة محتاجًا إلى فحص منفصل. إذا عدّلت الوقف لذلك الحد، فأعد حساب الحجم. لا تتوقع قرار الدخول؛ تحسب الأداة «كم»، ولا تحسم «هل أدخل» أبدًا.
S5 · النطاق اليومي مقابل ATR مع تنبيه
Pine Script v6 · مؤشرأداة وعي بالتقلب، كمؤشر داخل اليوم: تعرض على الأعمدة الحية النسبة التي «استهلكها» السوق من ATR اليومي، وتنبه عند عبور عتبة؛ وهي لحظة للرجوع إلى الخطة، لا للمطاردة. تُجلب البيانات اليومية دون استشراف أو قيم مستقبلية؛ وعلى الأعمدة التاريخية يحتفظ request.security بآخر قيمة يومية مؤكدة حتى نهاية فترة D التالية، وتظهر نتيجة تلك الفترة الجديدة على عمودها الأخير داخل اليوم. في الوقت الفعلي يجلب نطاق شمعة D الحالية وATR قيد التكوّن، لذلك قد تتغير قراءات سابقة بعد إعادة التحميل، أي إعادة الرسم. اليوم هو شمعة D لمزود البيانات، لا يوم تقويمي فيEurope/Warsaw. يتغير ATR في المقام خلال اليوم أيضًا؛ و100% ليست حدًا لمدى تحرك السعر. لا تستطيع الطريقة إعادة بناء عبورات العتبة المتعاقبة اليوم على الأعمدة التاريخية.
//@version=6
indicator("النطاق اليومي مقابل ATR (أداة للتوعية)", overlay=false)
if not timeframe.isintraday
runtime.error("استخدم رسمًا داخل اليوم قائمًا على الزمن وبفاصل أقل من 1D.")
atrLen = input.int(14, "فترة ATR", minval=2)
warnPct = input.int(80, "تنبيه عندما يبلغ نطاق اليوم نسبة % من ATR", minval=10, maxval=200)
// تاريخيًا: آخر قيمة D مؤكدة، تُحدّث في نهاية كل فترة D.
// في الوقت الفعلي: قيم D قيد التكوّن؛ قد يُعاد رسم القراءات الآنية السابقة بعد إعادة التحميل.
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, "نطاق اليوم كنسبة % من ATR", linewidth=2)
hline(100, "100% من ATR")
hline(warnPct, "مستوى التنبيه", linestyle=hline.style_dotted)
alertcondition(ta.crossover(rangePct, warnPct),
title="بلغ النطاق نسبة % من ATR",
message="بلغ النطاق اليومي نسبتك المحددة من ATR — أعد قراءة الخطة قبل أي دخول جديد.")
تحصل على لوحة أسفل الرسم وشرط تنبيه؛ أنشئ التنبيه بنفسك في المنصة بعد إضافة المؤشر، واختر «بلغ النطاق نسبة % من ATR». استخدم شموعًا عادية داخل اليوم قائمة على الزمن؛ فقد تختلف خصائص بيانات Heikin Ashi/Renko. القراءة المفقودةna تعني عدم توافر ATR أو البيانات المطلوبة، لا0%. يتطلب الشرط انتقالًا من قيمة≤ العتبة إلى قيمة> العتبة؛ ومجرد البقاء فوقها لا يطلق تنبيهًا جديدًا. يقصر “Once Per Bar Close” التنبيهات على إغلاق شمعة داخل اليوم، لكنه لا يؤكد شمعة D كلها. أعد إنشاء التنبيه بعد تغيير المعلمات. لا تتوقع إشارة اتجاهية؛ تقول القراءة المرتفعة «الحركة حدثت بالفعل»، ودليل الأنماط يحدد ما تفعل.
S6 · نوافذ جلسات خطة التداول على الرسم
Pine Script v6 · مؤشرالقسم3 من الخطة، الملحق E، مرسومًا على الشاشة: يميز الساعات التي يُسمح لك فيها بفتح مراكز، وينبه عند إغلاق النافذة. أدخل الأوقات بالمنطقة Europe/Warsaw؛ يراعي معرّف IANA نظام CET/CEST. افتراضيًا تنطبق النوافذ من الاثنين للجمعة، ويوسعها خيار لكل الأيام. يؤكد التظليل وقت الخطة فقط، لا شروط الدخول الأخرى. استخدم شموعًا عادية داخل اليوم قائمة على الزمن.
//@version=6
indicator("نوافذ جلسات خطة التداول", overlay=true)
if not timeframe.isintraday
runtime.error("استخدم رسمًا داخل اليوم قائمًا على الزمن وبفاصل أقل من 1D.")
tz = input.string("Europe/Warsaw", "المنطقة الزمنية للنوافذ")
win1 = input.session("0900-1200", "النافذة 1")
win2 = input.session("1400-1700", "النافذة 2")
weekdaysOnly = input.bool(true, "من الاثنين إلى الجمعة فقط")
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="داخل نافذة الخطة")
windowJustClosed = inWin[1] and not inWin
alertcondition(windowJustClosed,
title="أُغلقت نافذة الخطة",
message="أُغلقت للتو نافذة تداولك — أدر المراكز المفتوحة فقط، دون دخول جديد (الخطة، القسم 3).")
تحصل على تظليل الخلفية خلال ساعات التداول وشرط تنبيه لنهاية النافذة باسم «أُغلقت نافذة الخطة»؛ أنشئ التنبيه في المنصة بعد إضافة المؤشر. يرصد أول شمعة خارج النافذة تلي شمعة داخلها، فلا يضمن إخطارًا في وقت الإغلاق الدقيق؛ فلا فحص دون شمعة جديدة وتحديث بيانات. استخدم إطارًا تتوافق افتتاحاته وإغلاقاته مع حدود النافذة. مثلًا، علىM15، لنافذة09:00–12:00 مع توافر شمعة12:00، ينتهي التظليل عند12:00 وينشط الشرط في أول شمعة خارج النافذة. قد يخطر “Once Per Bar” عند تحديثها الأول، و“Once Per Bar Close” عند إغلاقها فقط. تشكل النوافذ المتداخلة اتحادًا؛ فلا تُغلق الثانية بنهاية الأولى. أعد إنشاء التنبيه بعد تغيير المواعيد. لا تتوقع منع الأوامر؛ يذكّرك المؤشر بالخطة، وتفرضها قائمة ما قبل الصفقة.
ستة مقاطع بعناوين في ملف نصي واحد، وتعليمات الإعداد وإصدارات المكتبات، ثم CSV الاختبار والمخرجات المتوقعة؛ لأرشفتها بجانب الدفتر أو حفظها في مستودعك. يجمع TXT لغات مختلفة؛ لا تشغّل الملف كله كـPython. اختر S1+S2+S3 أوS4 المستقل أو مؤشر Pine واحدًا.
الأسئلة الشائعة
لماذا تبقى الأسماء التقنية بالإنجليزية، وكيف تُقدّم التعليقات في النسخة العربية من الدورة ذات الأصل البولندي؟
اصطلاح هذه الحزمة إبقاء المعرّفات وأسماء API بالإنجليزية لتتوافق مع توثيق pandas وPine Script ورسائل الخطأ الإنجليزية؛ وتتبع ورشة الذكاء الاصطناعي الاصطلاح نفسه للأسماء في موجّهات الشفرة، كما في الملحق H وP3. في الأصل البولندي تشرح الأوصاف البولندية حول المقاطع ماذا تفعل الشفرة ومتى تُستخدم، والتعليقات الإنجليزية داخلها كيف تعمل؛ وفي النسخة العربية تُترجم الشروح والتعليقات وتسميات المخرجات للقارئ، وتبقى المعرّفات وواجهات API دون تغيير. الاستثناء في النسخة البولندية من الموجّه P5، أي التعليقات البولندية لشفرة مولّدة لك تحديدًا، يخص الشفرة المخصصة لمرة واحدة، لا اصطلاح المكتبة الأصلية.
كيف أشغّل مقاطع Python؟
11.8 يقودك خطوة بخطوة لتثبيت Python والبيئة والحزم؛ تكفي pandas و matplotlib لهذه الحزمة. ادمج المقاطع S1–S3 في ملف واحد باسم analiza_dziennika.py ، مع S1 في الأعلى، وشغّل python analiza_dziennika.py في المجلد الذي يحوي تصدير الدفتر؛ ويعمل S4 مستقلًا. يشير المسار النسبي CSV_PATH إلى مجلد العمل في الطرفية. ابدأ بـCSV الاختبار، وحلّل نسخة من دفترك الفعلي؛ ويُستبدل equity_curve.png في التشغيل التالي. إذا أعادت الطرفية خطأ لا تفهمه، فالصق الشفرة والرسالة الكاملة في مراجعة P3 من الملحق H، بدل التخمين.
هل يمكنني تعديل هذه المقاطع وتوسيعها؟
لهذا وُجدت؛ فهذه حزمة أولية. من التوسعات الطبيعية مؤشرات لكل إعداد، بالتجميع حسب عمود setup قبل استدعاء دالة S2، أو التصفية حسب error_code لحساب القيمة المتوقعة للتنفيذ الخالي من الأخطاء، أو منحنيات منفصلة لفئتي A+/B. قاعدتان للتعديل: مرّر كل تغيير عبر مراجعة P3، خصوصًا ما يخص request.security فيPine، وحدّد إصدارات تعريفات المؤشرات وقواعد الاستراتيجية معًا. أصلح خطأ الحساب فورًا وأعد حساب الفترات المقارنة بالطريقة نفسها؛ ووثّق تغيير قواعد الاستراتيجية في بروتوكول الاختبار، الملحق N واختبره على بيانات جديدة. لا تبرر نهاية الربع وحدها التغيير، ولا يبرر كونك في منتصفه إبقاء خطأ.
لماذا لا تتضمن الحزمة استراتيجيات أو مستشارين آليين EAs؟
للسبب نفسه الذي يمنع ورشة الذكاء الاصطناعي من توليد إشارات: الاستراتيجية الجاهزة من الإنترنت مجهولة الأفضلية والافتراضات ولا صلة لها بخطتك؛ وEA ينفّذ منطق غيرك في حسابك تفويض لقرارات تدفع تكلفتها وحدك. تقوّي شفرة الدورة العملية بالقياس والتصوير والالتزام بالخطة، بدل استبدالها. إذا أردت أتمتة استراتيجيتك المختبرة، يمر الطريق عبر الاختبار التاريخي في15.4 وبروتوكول الملحق N ومراجعة الشفرة P3، لا بنسخ برامج «رابحة».
math.floor في S4 بدل round؛ تقرّب الآلة إلى أسفل بلا جدال، ويقرّب الإنسان إلى أعلى مع تبرير.مواد مرتبطة من الدورة
- 11.8 Python في التداول — إعداد البيئة والبرنامج الأول والعمل مع الحزم
- الملحق F — جدول الدفتر — تنسيق CSV الذي يقرؤه S1–S3، والمؤشرات نفسها كصيغ جدول بيانات
- الملحق H، الموجّه P3 — مراجعة كل تعديل لهذه الشفرة: الاستشراف وإعادة الرسم والأخطاء المنطقية
- قسم الأدوات — الحاسبات — قيمة النقطة وحجم المركز في المتصفح للتحقق من نتائج S4
- الملحق E — قالب الخطة — نوافذ التداول والحدود التي يرسمها S6
- 15.10 تدقيق الاستراتيجية — التفسير المنضبط للأرقام التي تنتجها الحزمة
المصادر
- الوثائق: pandas 3.0.5 و matplotlib 3.11.1 للدوال المستخدمة فيS1–S3؛ Python: قراءة CSV و حساب الكسور Fraction للتحقق من التنسيق وحساب عدد خطوات اللوت بدقة؛ شُغّلت المقاطع S1–S4 على بيانات اصطناعية في17 سبتمبر2026 باستخدام Python 3.12.10؛ وTradingView Pine Script v6: الأطر الزمنية والبيانات الأخرى, الجلسات, الوقت والمناطق الزمنية, التنبيهات request.security مع معلمة lookahead وإعادة الرسم وhline وinput.session وalertcondition؛ روجعت شفرة S5–S6 مقابل الوثائق دون ترجمة برمجية.
- من الدورة: 11.8 Python في التداول البيئة، 15.9 تعريفات المؤشرات وتنسيق الدفتر، 15.10 مبادئ استخلاص الاستنتاجات؛ والحزمة تطبيقها العملي المختصر.
- Van K. Tharp، Trade Your Way to Financial Freedom، الطبعة2، McGraw-Hill 2007؛ مضاعفات R والقيمة المتوقعة، اللغة المشتركة بين S2 والجدول F والموجّه P5.