Technický článek

Vzorce pro dluhopisy a pokladniční poukázky v Delphi s HotXLS

HotXLS vyhodnocuje finanční funkce Excelu pro dluhopisy a pokladniční poukázky nativně v Delphi a C++Builder: PRICE, YIELD, DURATION, MDURATION, šest primitiv kupónových dat, trojici pro pokladniční poukázky, rodinu diskontních funkcí a francouzské funkce odpisů. Počítají se uvnitř vlastního výpočetního enginu knihovny, takže sešit, který oceňuje portfolio dluhopisů, se přepočítá na serveru bez Excelu a bez doplňku Analysis ToolPak kdekoli v dohledu

Tyto funkce dřív žily v doplňku Analysis ToolPak, což je důvod, proč si stále nesou pověst něčeho neohrabaného. Od Excelu 2007 jsou součástí standardní sady funkcí a v souborovém formátu jsou zapsané holé, bez prefixu _xlfn., který nesou skutečně novější funkce. Sešit, který je používá, je obyčejný sešit; jedinou otázkou je, zda ať už ho přepočítává cokoli, tyto funkce zná

Co musí engine kupónových dat zvládnout správně

Každý výpočet dluhopisu stojí na stejných primitivech: kolik dní od posledního kupónu, kolik dní má aktuální kupónové období, kolik dní zbývá do dalšího kupónu, kdy tyto kupóny připadají a kolik jich zbývá. Jsou to COUPDAYBS, COUPDAYS, COUPDAYSNC, COUPPCD, COUPNCD a COUPNUM, a volá je každá funkce pro cenu i výnos

Netriviální je z toho argument báze. Ve hře je pět konvencí počítání dnů — 30/360 US, actual/actual, actual/360, actual/365 a 30/360 evropská — a ty se neshodnou na otázkách typu, co se stane, když datum vypořádání připadne na 31. den měsíce, nebo jak se chová únorové kupónové datum v přestupném roce. Zvládnout jednu konvenci správně a ostatní jen aproximovat vyprodukuje výsledky, které vypadají věrohodně a jsou špatné o pár bazických bodů, což je u velké pozice reálné peníze

HotXLS implementuje všech pět v samostatném vnořeném enginu kupónových dat sdíleném každou funkcí, která ho potřebuje, takže PRICE a DURATION se nemohou navzájem neshodnout na tom, kde kupónová data leží

Engine kupónových dat HotXLS pro Delphi: vstupy dluhopisu a zvolená báze počítání dnů zásobují šest primitiv COUP sdílených funkcemi PRICE, YIELD, DURATION a MDURATION
Všech pět bází počítání dnů zásobuje jeden vnořený engine kupónových dat sdílený každou finanční funkcí v HotXLS, takže PRICE a DURATION se nikdy nemohou neshodnout na tom, kam kupónová data padají

Cena a výnos v sešitu

Na volajícím kódu není nic zvláštního: zapište vzorce, přepočítejte, čtěte hodnoty. V tom je smysl — sešit je model a vaše aplikace v Delphi je kalkulačka:

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);   // vypořádání
    Sheet.Cells[2, 1].Value := EncodeDate(2034, 11, 15);  // splatnost
    Sheet.Cells[3, 1].Value := 0.0425;                    // kupónová sazba
    Sheet.Cells[4, 1].Value := 0.0391;                    // požadovaný výnos
    Sheet.Cells[5, 1].Value := 100;                       // umoření
    Sheet.Cells[6, 1].Value := 2;                         // frekvence
    Sheet.Cells[7, 1].Value := 1;                         // báze: actual/actual

    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;

Data se vkládají jako skutečné datové hodnoty, ne jako řetězce. Textové datum funguje v Excelu, protože ho Excel převede, a převod závisí na lokalizaci, což je přesně ten druh závislosti, kterou by přepočet na straně serveru neměl mít. Pravidla datového systému, která pod tím vším leží, popisuje článek pořadová čísla dat a systém 1904

Výnos nemá uzavřený vzorec, a to má důsledky

PRICE je přímý výpočet: diskontujte peněžní toky, sečtěte je. YIELD je jeho inverzí a pro dluhopis s více než jedním zbývajícím kupónem nemá řešení v uzavřeném tvaru, takže se musí řešit numericky. HotXLS používá bisekční solver, který konverguje spolehlivě, ne rychle

Z toho plynou dva praktické důsledky. Výnos je měřitelně dražší než cena, takže přecenění portfolia, které počítá výnosy pro deset tisíc pozic, stojí citelně víc než to, které počítá ceny, a vyplatí se vědět, který ze dvou váš model skutečně potřebuje. A výnos, který nelze ohraničit — protože vstupy popisují dluhopis, který žádný výnos neocení na zadanou hodnotu — vrátí chybu místo špatného čísla, což je správné chování a to, které byste měli otestovat

V HotXLS na Delphi je PRICE jeden přímý průchod diskontovanými peněžními toky, zatímco YIELD nemá uzavřený tvar a řeší se bisekční smyčkou, která vrátí chybu, když neexistuje žádné ohraničení
PRICE je jeden přímý průchod přes diskontované peněžní toky, zatímco YIELD nemá uzavřený tvar a ohraničuje se a bisekcí řeší, přičemž vrátí chybu místo špatného čísla, když vstupy nelze ocenit

Pokladniční poukázky jsou vlastní rodina

Poukázky jsou diskontní nástroje bez kupónů, takže používají TBILLPRICE, TBILLYIELD a TBILLEQ, ne funkce pro dluhopisy. TBILLEQ převádí diskontní sazbu na výnos ekvivalentní dluhopisu a má zdokumentovanou zvláštnost, o které stojí za to vědět: pro splatnosti delší než 182 dní je převod kvadratický, ne lineární, protože cenný papír přesahuje jedno pololetní období

Vložení poukázky do PRICE místo toho, s nulovým kupónem a frekvencí, nevyprodukuje stejné číslo. Rodina diskontních nástrojů — DISC, INTRATE, RECEIVED, PRICEDISC a YIELDDISC — existuje přesně proto, že tyto nástroje se kótují a vypořádávají jinak

Zbytek sady na jednom místě

Nad rámec dluhopisů a poukázek stejná dávka pokrývá funkce, které je v reálných modelech obklopují. PRICEMAT a YIELDMAT zpracovávají cenné papíry, které platí úrok při splatnosti. ACCRINTM pro ně počítá naběhlý úrok. EFFECT a NOMINAL převádějí mezi efektivní a nominální roční sazbou, což je převod, který se ručně nejčastěji dělá špatně. CUMIPMT a CUMPRINC dávají kumulativní úrok a jistinu za rozsah období. FVSCHEDULE aplikuje sekvenci různých sazeb v pořadí, přičemž přijímá jak oblast, tak skalár

DOLLARDE a DOLLARFR převádějí mezi desetinnou a zlomkovou dolarovou kotací, což má význam pro každý nástroj stále kótovaný v třicetinách. A AMORDEGRC a AMORLINC implementují francouzské metody odpisů, které vyžadují francouzská účetní pravidla, ne jen volitelné vymoženosti

// Převod sazby, který lidé ručně běžně pletou
Sheet.Cells[1, 3].Formula := '=EFFECT(0.0425,12)';   // nominální na efektivní
Sheet.Cells[2, 3].Formula := '=NOMINAL(0.043338,12)'; // a zpět

// Kumulativní úrok za první dva roky 25letého úvěru
Sheet.Cells[4, 3].Formula :=
  '=CUMIPMT(0.0389/12,300,340000,1,24,0)';

// Projekce s proměnlivou sazbou: 3 procenta, pak 3,5, pak 4
Sheet.Cells[6, 3].Formula := '=FVSCHEDULE(10000,{0.03;0.035;0.04})';

Ověřování implementace, kterou jste nenapsali sami

Finanční funkce jsou jedna oblast, kde "vrací to číslo" není důkazem ničeho. Číslo je věrohodné svou konstrukcí a chyba v konvenci počítání dnů posune výsledky o částku příliš malou na to, aby si jí kdokoli všiml, a příliš velkou na to, aby byla přijatelná

Test, který skutečně funguje, je diferenciální. Sestavte tabulku reprezentativních nástrojů — jeden dluhopis na každou bázi počítání dnů, jeden, který se vypořádává na konci měsíce, jeden, který přesahuje únor přestupného roku, jednu poukázku pod 182 dní a jednu nad — spočítejte hodnoty jednou v Excelu, uložte je jako očekávané výsledky a porovnávejte s nimi po každém upgradu knihovny. Pozice přesahující kupónové datum a vypořádání na 31. dni jsou místa, kde se implementace rozcházejí, takže obojí zahrňte záměrně

Sada diferenciální validace pro dluhopisové a pokladniční funkce HotXLS v Delphi: reprezentativní nástroje včetně případů přestupného roku a konce měsíce se spočítají jednou v Excelu a porovnávají po každém upgradu knihovny
Diferenciální sada ocení reprezentativní nástroje jednou v Excelu, uloží hodnoty jako očekávání a porovnává je po každém upgradu HotXLS, takže odchylka o bazické body se nemůže schovat za věrohodně vyhlížející výstup

Pro samotné sešity jsou dva společníci této funkce výpočetní engine, který rozhoduje, co přepočítat, popsaný v článku inkrementální přepočet a graf závislostí, a statistická rodina popsaná v článku statistické distribuční funkce. Společně umožňují, aby finanční model běžel na serveru bez dozoru, což byl celý důvod pro jejich nativní implementaci

Dluhopisové finance, statistika, inženýrské funkce a přepočtový engine jsou dodávány v jedné knihovně pro Delphi a C++Builder; úplný seznam funkcí najdete na stránce komponenty HotXLS Delphi spreadsheet component