أسس كتابة مؤشرات المستخدمين

مدخل

إن الغرض من هذه المقالة ، هو تبيان مبادئ إنشاء مؤشرات المستخدم في مثال و معاينة " المطبات " التي قد تواجه المبرمجين الذين يجرون خطواتهم الاولى في فهم لغة NTL+ .


أثناء وضع خوارزمية مؤشر المستخدم ، سيتوجب عليك الكيفية التي سيتم بواسطتها حساب القيم المُسجلة في الصوان ( الذاكرة المؤقتة Buffer ) للمؤشر و كيف سيظهر على الشاشة. إن التشكيل الصحيح لهذه القيم يُعدّ الهدف الآخير أثناء انجاز المؤشر .


كمثال ، سنقوم بإنشاء مؤشر يُبين الفرق بين كمية البارات ( القضبان ) التي سعر الاقفال لديها أكبر من سعر الفتح و كذلك يُبين الفرق بين كمية البارات التي سعر الاقفال لديها أقل من سعر الفتح . ستتجمع هذه الفروقات خلال الفترات الاخيرة ( n ). سنقوم بعرض مؤشرنا في نافذة خاصة و عرضها على شكل رسم بياني .


كتابة التعليمات البرمجية النصية ( كود السكريبت )

ستكون الخوارزمية بسيطة و مفهومة و ذلك حتى نتمكن بسهولة من تجربة عمل المؤشر. سنقوم و لكل (i) بار ، بتحليل البارات (n) السابقة له و سنقوم بتشكل الاحصائية ، التي بها أثناء العثور على البار الصاعد سنقوم بإضافة وحدة للقيمة الناتجة ، أما في حال وجدنا بار هابط ، فسنقوم بطرح وحدة .

img

لننظر في كود هذا المؤشر


في البداية يجب الاعلان عن كل المتغيرات التي سيتم استخدامها في مؤشرنا .

#set_indicator_separate
double ExtMapBuffer1[];
int ExtCountedBars=0;
extern int period = 10;

يُبين المُعالج التمهيدي #set_indicator_separate بأننا سنقوم بإظهار الرسم البياني في نافذة مستقلة و لن يتوضع على الرسم البياني الأساسي للسعر. في السطر التالي يُعلن عن المجموعة ( هيكل البيانات - Array data structure ) العريضة ExtMapBuffer1 الذي سيتم فيه حفظ قيم صوان المؤشر . نرجوا الانتباه ، إلى أننا لا نُبيّن حجم هذه المجموعة كون أن المُحوّل البرمجي (Compiler ) يُحددّ بذاته الحجم المطلوب للذاكرة المُعطاة .


عملياً ، تُحفظ جميع احداثيات النقط المشاركة في العرض في مجموعة ExtMapBuffer1 ، أما إحداثيات السينات فإنها تُحدد بواسطة مؤشر عناصر المجموعة. من ثم نقوم بتهيئة المتغيرة ExtCountedBars بالقيمة صفر 0 .سيتم حفظ كمية من البارات التي تم حسابها في هذه المتغيرة . بهذا الشكل ، لن نكون بحاجة في كل مرة القيام بحساب جميع البارات ، الامر الذي يُسرع بشكل كبير من حساب قيم المؤشر ، و سيتحرك الرسم البياني للمؤشر بشكل أسرع. في السطر اللاحق يتم الاعلان المتغيرة period لحفظ كمية الفترات التي يحتسب فيها المؤشر الاحصائية المعطاة. تجدر الاشارة هنا الى أنّ استخدام المُعدّل (modifier ) extern يمكننا من تغيير بارامتر period من خلال خاصيات المؤشر بدون الحاجة الى اعادة التجميع .


لننظر في الوظيفة Initialize() التي سنبين فيها الاعدادات الاساسية لمؤشرنا .


int Initialize() { Indicator.SetIndexCount(1); Indicator.SetIndexBuffer(0,ExtMapBuffer1); Indicator.SetIndexStyle(0,ltHistogram,lsSolid,5,clrBlue); return(0); }

إن طريقة SetIndexCount عنصر Indicator يُحدد كمية الصوانات لقيم المؤشرات. الصوان ذو القيمة ExtMapBuffer1 لدينا هو واحد / لذلك نُبين الوحدة في كمسة البارامتر الوحيد . كذلك سنكون بحاجة الى ربط رقم الصوان بمجموعة قيم الصوان. إن هذا الربط يُبين في سطر Indicator.SetIndexBuffer(0,ExtMapBuffer1) / حيث مُحدّد ، بأن خصائص المؤشر الصفر يُستخدم لرسم القيم من صوان ExtMapBuffer1 .


في السطر التالي ، نُعطي مؤشرنا الخصائص. أول بارامتر طريقة SetIndexStyle يُعطي رقم الصوان. و هي قيمة 0 ، و الذي كنّا قد اشرنا اليه في SetIndexBuffer. يُحدد البارامتر الثاني نوع الرسم : و هو الرسم البياني. في البارامتر الثالث نُعطي نوع الخطوط lsSolid ( يمكن هنا عملياً إعطاء أية قيمة ، حيث أن هذا البارامتر يؤثر فقط على الخط و على الرسم البياني بسمك واحد ). في باقي البارمترات نُعطي للخط سماكة 5 و اللون أزرق على شكل ثوابت clrBlue ( كما يمكن وضع اللون في صيغة RGB ، كمثل 0x0000FF ).


من ثم تأتي وظيفة Run() و التي تنفذ عملية المراجعات الاساسية و تُشغل وظيفة المستخدم draw(). تُنفّذ وظيفة draw() الحساب بأكمله .


int Run() { ExtCountedBars=Indicator.Calculated; if (ExtCountedBars < 0) { System.Print("Error"); return(-1); } draw(); return(0); }

نقوم بإدخال كمية البارات التي لم تتغير منذ لحظة آخر استدعاء في المتغيرة ExtCountedBars . هذا و لقد كنا قد قمنا بإحتساب كل شيء لهذه القيم ، و لذلك لا داعي هناك للحساب من البداية. من ثم نقوم بوضع في حال ExtCountedBars < 0 نوقف عمل المؤشر. من ثم يتم استدعاء الوظيفة draw() التي تحتسب القيم و تدخلهم في صوان المؤشر .


void draw() { int pos=Chart.Bars-ExtCountedBars-1; int value; while(pos>=0) { value=0; for(int i=pos;i < pos+period && i < Chart.Bars-1;i++) { if(Open[i] < Close[i]) value+=1; else value-=1; } ExtMapBuffer1[pos]=value; pos--; } }

في السطر «int pos=Chart.Bars-ExtCountedBars-1;» نقوم بتحديد الموضع ، الذي نبدأ منه بحساب القيم ، متحركين من اقدم الباينات حتى أحدثها. في حال كان المجموع العام للبارات مساوياً Chart.Bars ، فإن " أبعد " عنصر سيكون له الفهرس Chart.Bars-1 أمّا مع حسبان البارات المحتسبة فسيكون : Chart.Bars-ExtCountedBars-1 . يُستخدم المتغير value لتجميع احصائيتنا. من ثم ، في الدورة من Chart.Bars-ExtCountedBars-1 حتى الصفر 0 ، فإننا لكل بار نقوم بجمع الاحصائية و ليس لأكثر من period المواقف السابقة ( لا يجب أن لا نحتسب القيم للبيانات الغير مُحمّلة ) .


نقوم بجمع الكود بأكمله :


#set_indicator_separate double ExtMapBuffer1[]; int ExtCountedBars=0; extern int period = 10; int Initialize() { Indicator.SetIndexCount(1); Indicator.SetIndexBuffer(0,ExtMapBuffer1); Indicator.SetIndexStyle(0,ltHistogram,lsDot,5,clrBlue); return(0); } int Run() { ExtCountedBars=Indicator.Calculated; if (ExtCountedBars < 0) { System.Print("Error"); return(-1); } draw(); System.Print("ExtCountedBars="+ExtCountedBars); return(0); } void draw() { int pos=Chart.Bars-ExtCountedBars-1; int value; while(pos>=0) { value=0; for(int i=pos;i < pos+period && i < Chart.Bars-1;i++) { if(Open[i] < Close[i]) value+=1; else value-=1; } ExtMapBuffer1[pos]=value; pos--; } }

الان نقوم بتحسين مؤشرنا بعض الشيء: سنقوم بعرض العواميد السالبة بلون واحد ، أما الايجابية – بلون آخر. مع هذا ، سيكون كل بار من البارات بلونين. لذلك سنكون بحاجة لأربعة صوانات.


#set_indicator_separate double ExtMapBuffer1[]; double ExtMapBuffer2[]; double ExtMapBuffer3[]; double ExtMapBuffer4[]; int ExtCountedBars=0; extern int period = 10; int Initialize() { Indicator.SetIndexCount(4); Indicator.SetIndexBuffer(0,ExtMapBuffer1); Indicator.SetIndexStyle(0,ltHistogram,lsDot,5,clrBlue); Indicator.SetIndexBuffer(1,ExtMapBuffer2); Indicator.SetIndexStyle(1,ltHistogram,lsDot,5,clrGreen); Indicator.SetIndexBuffer(2,ExtMapBuffer3); Indicator.SetIndexStyle(2,ltHistogram,lsDot,5,clrRed); Indicator.SetIndexBuffer(3,ExtMapBuffer4); Indicator.SetIndexStyle(3,ltHistogram,lsDot,5,clrLime); return(0); } int Run() { ExtCountedBars=Indicator.Calculated; if (ExtCountedBars < 0) { System.Print("Error"); return(-1); } draw(); return(0); } void draw() { int pos=Chart.Bars-ExtCountedBars-1; int value; while(pos>=0) { value=0; for(int i=pos;i < pos+period && i < Chart.Bars-1;i++) { if(Open[i] < Close[i]) value+=1; else value-=1; } if(value>0) { ExtMapBuffer1[pos]=value; ExtMapBuffer2[pos]=0; ExtMapBuffer3[pos]=1; ExtMapBuffer4[pos]=0; } if(value==0) { ExtMapBuffer1[pos]=0; ExtMapBuffer2[pos]=0; ExtMapBuffer3[pos]=0; ExtMapBuffer4[pos]=0; } if(value < 0) { ExtMapBuffer1[pos]=0; ExtMapBuffer2[pos]=value; ExtMapBuffer3[pos]=0; ExtMapBuffer4[pos]=-1; } } pos--; } }

النسخة الجديدة للمؤشر بالبارات المختلفة الالوان :

img

اثناء كتابة كود المؤشر ، قد تصادفك رسالة في السجل : «run fuction call failed» ( فشل استدعاء وظيفة run ). إن مثل هذا الخطأ ، عادة ما يظهر اثناء تسجيل القيم كعناصر ذات مؤشرات غير موجودة ، و لذلك أثناء ظهور مثل هذه الرسالة ، يجب التأكد بدقة من قيم مؤشر مجموعات الصوان .


الخلاصة

لقد قمنا في هذه المقالة بإنشاء مؤشرنا خطوة خطوة. مع العلم بأن انشاء المؤشر تمّ بشكل حاولنا من خلاله اقصى المستطاع التبسيط لفهم كود السكريبت بلغة NTL+. قد لا يكون هناك نفع لهذا المؤشر في تجارتك ، لا بل حتى نحن لم نضع هذا الهدف نصب أعيننا . كل ما قمنا به ، هو أننا ضربنا مثالاً على إنشاء المؤشر ، الامر الذي سيفيدك اثناء كتابتك لاي مؤشر كان .