مقال تقني

صيغ السندات وأذون الخزانة في Delphi باستخدام HotXLS

يُقيِّم HotXLS دوال Excel المالية الخاصة بالسندات وأذون الخزانة أصليًا في Delphi و C++Builder: PRICE و YIELD و DURATION و MDURATION، والدوال الأولية الست لتواريخ القسائم، وثلاثية أذون الخزانة، وعائلة الخصم، ودوال الاستهلاك الفرنسية. وتُحسب داخل محرك الصيغ الخاص بالمكتبة نفسه، بحيث يعيد مصنف يُسعِّر محفظة سندات الحساب على خادم دون أي Excel ودون إضافة Analysis ToolPak في أي مكان

كانت هذه الدوال تعيش في Analysis ToolPak، ولهذا لا تزال تحمل سمعة الصعوبة. ومنذ Excel 2007 أصبحت جزءًا من مجموعة الدوال القياسية وتُكتب عارية في صيغة الملف، دون بادئة _xlfn. التي تحملها الدوال الأحدث فعليًا. ومصنف يستخدمها مصنف عادي؛ والسؤال الوحيد هو ما إذا كان أي شيء يعيد حسابه يعرف الدوال

ما الذي يجب أن يصيبه محرك تواريخ القسائم بدقة؟

يرتكز كل حساب سند على الأوليات نفسها: كم يومًا مضى منذ آخر قسيمة، وكم يومًا في فترة القسيمة الحالية، وكم يومًا حتى القسيمة التالية، ومتى تقع تلك القسائم، وكم منها يتبقى. وهذه هي COUPDAYBS و COUPDAYS و COUPDAYSNC و COUPPCD و COUPNCD و COUPNUM، وتستدعيها كل دالة تسعير وعائد

وما يجعلها غير تافهة هو وسيط الأساس. فخمس اتفاقيات لحساب الأيام قيد الاستخدام — 30/360 الأمريكية، وفعلي/فعلي، وفعلي/360، وفعلي/365، و30/360 الأوروبية — وهي تختلف حول أسئلة مثل ما يحدث عندما يقع تاريخ التسوية في اليوم 31 من شهر، أو كيف يتصرف تاريخ قسيمة فبراير في سنة كبيسة. وإصابة اتفاقية واحدة بدقة وتقريب البقية ينتج نتائج تبدو معقولة وهي خاطئة ببضع نقاط أساس، وهذا مال حقيقي على مركز كبير

وينفّذ HotXLS الخمس جميعًا في محرك تواريخ قسائم متداخل ومكتفٍ بذاته مشترك بين كل دالة تحتاجه، بحيث لا يمكن لـ PRICE و DURATION أن يختلفا حول مواضع تواريخ القسائم

محرك تواريخ القسائم في HotXLS لـ Delphi: مدخلات السند وأساس حساب الأيام المختار يغذّيان ست دوال أولية من نوع COUP مشتركة بين PRICE و YIELD و DURATION و MDURATION
تغذّي أسس حساب الأيام الخمسة جميعها محرك تواريخ قسائم متداخل واحد مشترك بين كل دالة مالية في HotXLS، بحيث لا يمكن لـ PRICE و DURATION أبدًا أن يختلفا حول مواضع تواريخ القسائم

التسعير والعائد في مصنف

لا شيء خاص في كود الاستدعاء: اكتب الصيغ، وأعِد الحساب، واقرأ القيم. وهذا هو بيت القصيد — فالمصنف هو النموذج، وتطبيق Delphi الخاص بك هو الآلة الحاسبة:

uses
  lxHandleX;

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
begin
  Book := TXLSXWorkbook.Create;
  try
    Sheet := Book.Sheets.Add('Bond');
    Sheet.Cells[1, 1].Value := EncodeDate(2026, 3, 15);   // تاريخ التسوية
    Sheet.Cells[2, 1].Value := EncodeDate(2034, 11, 15);  // تاريخ الاستحقاق
    Sheet.Cells[3, 1].Value := 0.0425;                    // معدل القسيمة
    Sheet.Cells[4, 1].Value := 0.0391;                    // العائد المطلوب
    Sheet.Cells[5, 1].Value := 100;                       // قيمة الاسترداد
    Sheet.Cells[6, 1].Value := 2;                         // التكرار
    Sheet.Cells[7, 1].Value := 1;                         // الأساس: فعلي/فعلي

    Sheet.Cells[9, 1].Formula  := '=PRICE(A1,A2,A3,A4,A5,A6,A7)';
    Sheet.Cells[10, 1].Formula := '=DURATION(A1,A2,A3,A4,A6,A7)';
    Sheet.Cells[11, 1].Formula := '=MDURATION(A1,A2,A3,A4,A6,A7)';
    Sheet.Cells[12, 1].Formula := '=COUPNUM(A1,A2,A6,A7)';

    Book.Recalculate;

    Writeln(Format('price %.6f  Macaulay %.6f  modified %.6f  coupons %d',
      [Double(Sheet.Cells[9, 1].Value), Double(Sheet.Cells[10, 1].Value),
       Double(Sheet.Cells[11, 1].Value),
       Integer(Sheet.Cells[12, 1].Value)]));
  finally
    Book.Free;
  end;
end;

وتُدخَل التواريخ كقيم تاريخ حقيقية لا كسلاسل نصية. فالتاريخ النصي يعمل في Excel لأن Excel يُكرهه على النوع الصحيح، ويعتمد هذا الإكراه على اللغة المحلية، وهذا بالضبط نوع الاعتمادية التي يجب ألا تحملها إعادة حساب من جهة الخادم. وقواعد نظام التاريخ التي تقف تحت ذلك موصوفة في أرقام التاريخ التسلسلية ونظام 1904

العائد بلا صيغة مغلقة، ولذلك تبعات

PRICE حساب مباشر: اخصم التدفقات النقدية، واجمعها. أما YIELD فهو معكوسه ولا يملك حلاً بصيغة مغلقة لسند به أكثر من قسيمة متبقية، فيجب حله عدديًا. ويستخدم HotXLS حلاّل تنصيف يتقارب بموثوقية لا بسرعة

ولهذا نتيجتان عمليتان. العائد أغلى قياسًا من التسعير بشكل ملحوظ، بحيث تكلّف إعادة تقييم محفظة تحسب العائد لعشرة آلاف مركز أكثر بكثير مما تكلّفه حسابات تسعير فقط، ويستحق الأمر معرفة أيهما يحتاجه نموذجك فعليًا. وعائد لا يمكن إحاطته — لأن المدخلات تصف سندًا لا يمكن لأي عائد تسعيره عند القيمة المُعطاة — يُعيد خطأً بدلاً من رقم خاطئ، وهذا هو السلوك الصحيح والسلوك الذي يجب اختباره

في HotXLS على Delphi، تُحسب PRICE بتمريرة مباشرة واحدة على التدفقات النقدية المخصومة، بينما لا تملك YIELD حلاً مغلقًا وتُحل بحلقة تنصيف تُعيد خطأ عندما لا يوجد إطار احتواء
تُحسب PRICE بتمريرة مباشرة واحدة على التدفقات النقدية المخصومة، بينما لا تملك YIELD حلاً مغلقًا وتُحاط وتُنصَّف، فتُعيد خطأ بدلاً من رقم خاطئ عندما يتعذر تسعير المدخلات

أذون الخزانة عائلة قائمة بذاتها

الأذون أدوات خصم بلا قسائم، لذلك تستخدم TBILLPRICE و TBILLYIELD و TBILLEQ بدلاً من دوال السندات. وتحوّل TBILLEQ معدل خصم إلى عائد معادل للسند، ولها خصوصية موثَّقة تستحق المعرفة: فلآجال استحقاق تتجاوز 182 يومًا، يكون التحويل تربيعيًا لا خطيًا، لأن الأداة تمتد لأكثر من فترة نصف سنة واحدة

وإدخال أذن خزانة إلى PRICE بدلاً من ذلك، بقسيمة صفرية وتكرار، لا ينتج الرقم نفسه. وتوجد عائلة أدوات الخصم — DISC و INTRATE و RECEIVED و PRICEDISC و YIELDDISC — بالضبط لأن هذه الأدوات تُسعَّر وتُسوَّى بشكل مختلف

بقية المجموعة، في مكان واحد

وبعيدًا عن السندات والأذون، تغطي الدفعة نفسها الدوال التي تحيط بها في النماذج الحقيقية. تتعامل PRICEMAT و YIELDMAT مع الأدوات التي تدفع فائدة عند الاستحقاق. وتحسب ACCRINTM الفائدة المستحقة لتلك الأدوات. وتحوّل EFFECT و NOMINAL بين المعدلات السنوية الفعلية والاسمية، وهو التحويل الذي يُخطئ فيه معظم الناس يدويًا. وتعطي CUMIPMT و CUMPRINC الفائدة والأصل التراكميين على نطاق من الفترات. وتطبّق FVSCHEDULE سلسلة من المعدلات المختلفة بالتتابع، آخذة إما نطاقًا أو قيمة عددية

وتحوّل DOLLARDE و DOLLARFR بين تسعيرات الدولار العشرية والكسرية، وهذا مهم لأي أداة لا تزال مُسعَّرة بالأثلاث والثلاثين. وتنفّذ AMORDEGRC و AMORLINC طرق الاستهلاك الفرنسية، التي تفرضها قواعد المحاسبة الفرنسية لا خيارات مريحة اختيارية

// تحويل معدل يُخطئ فيه الناس يدويًا بشكل روتيني
Sheet.Cells[1, 3].Formula := '=EFFECT(0.0425,12)';   // اسمي إلى فعلي
Sheet.Cells[2, 3].Formula := '=NOMINAL(0.043338,12)'; // والعكس

// الفائدة التراكمية خلال أول سنتين من قرض مدته 25 سنة
Sheet.Cells[4, 3].Formula :=
  '=CUMIPMT(0.0389/12,300,340000,1,24,0)';

// إسقاط بمعدل متغير: 3 بالمئة، ثم 3.5، ثم 4
Sheet.Cells[6, 3].Formula := '=FVSCHEDULE(10000,{0.03;0.035;0.04})';

التحقق من تنفيذ لم تكتبه أنت

الدوال المالية هي المجال الوحيد الذي لا يكون فيه "إنها تُعيد رقمًا" دليلاً على أي شيء. فالرقم معقول بحكم البناء، وخطأ في اتفاقية حساب الأيام يُزيح النتائج بمقدار صغير جدًا بحيث لا يُلاحَظ وكبير جدًا بحيث لا يُقبَل

والاختبار الذي ينجح فعليًا هو اختبار تفاضلي. ابنِ جدول بيانات لأدوات تمثيلية — سند واحد لكل أساس حساب أيام، وسند تتم تسويته في نهاية شهر، وسند يمتد عبر فبراير في سنة كبيسة، وإذن أقل من 182 يومًا وآخر أكثر — واحسب القيم في Excel مرة واحدة، وخزّنها كنتائج متوقعة، واختبر مقابلها بعد كل ترقية للمكتبة. والمراكز التي تمتد عبر تاريخ قسيمة والتسويات في اليوم 31 هي حيث تتباعد التنفيذات، فأدرج كليهما عن قصد

مجموعة تحقق تفاضلي لدوال السندات وأذون الخزانة في HotXLS لـ Delphi: أدوات تمثيلية بما فيها حالات السنة الكبيسة ونهاية الشهر تُحسب مرة واحدة في Excel وتُختبر بعد كل ترقية للمكتبة
تُسعِّر مجموعة تفاضلية أدوات تمثيلية مرة واحدة في Excel، وتُخزِّن القيم كتوقعات وتختبرها بعد كل ترقية لـ HotXLS، بحيث لا يمكن لانحراف بمقدار نقاط أساس أن يختبئ خلف مخرجات معقولة المظهر

وبالنسبة للمصنفات نفسها، فإن الرفيقين لهذه الميزة هما محرك الحساب الذي يقرر ما يجب إعادة حسابه، الموصوف في إعادة الحساب التزايدية ومخطط الاعتمادية، والعائلة الإحصائية الموصوفة في دوال التوزيع الإحصائي. ومعًا هما ما يتيح لنموذج مالي أن يعمل دون إشراف على خادم، وهذا هو السبب الكامل لتنفيذهما أصليًا

يأتي تمويل السندات والإحصاء والدوال الهندسية ومحرك إعادة الحساب في مكتبة واحدة لـ Delphi و C++Builder؛ وتجد قائمة الميزات الكاملة على صفحة مكوّن HotXLS لجداول البيانات في Delphi