Historische Volatilität von Wertpapieren mit Math::Business::BlackScholes berechnen
Veröffentlicht von Thomas Fahle am (Permalink)
Math::Business::BlackScholes
Das CPAN-Modul Math::Business::BlackScholes - Black-Scholes option price model functions von Anders Johnson bietet neben Funktionen zur Berechnung der Preise von klassischen Put- bzw. Call-Optionen nach dem Black-Scholes-Modell auch eine Funktion zur Berechnung der historischen Volatilität von Wertpapieren.
In diesem Beitrag geht es ausschließlich um die historische Volatilität, alle anderen Funktionen des Moduls werden nicht besprochen.
Zentrierte historische Volatilität
Math::Business::BlackScholes berechnet die annualisierte historische Volatilität als Standardabweichung der logarithmischen Renditen (stetige Verzinsung), die auch als zentrierte historische Volatilität bezeichnet wird.
Beispiel: Historische Volatilität
Das folgende Beispiel ruft zunächst die historischen Börsenkurse der letzen 30 Tage mittels Finance::QuoteHist, das bereits hier beschrieben wurde, ab.
Im nächsten Schritt wird mittels der Funktion historical_volatility die annualisierte historische Volatilität berechnet. Die Funktion historical_volatility erwartet zwei Parameter: eine Referenz auf eine Liste der Schlusskurse und optional die Anzahl der Tradingtage pro Jahr (default 250 Tage).
Die Anzahl der Elemente in der Liste der Schlusskurse wird von historical_volatility als Anzahl der Tage gewertet, für welche die historische Volatilität berechnet werden soll. Wenn die Liste 30 Elemente enthält, wird die Vola über 30 Tradingtage berechnet - bei 50 Elementen über 50 Tradingtage. Wenn weniger als 10 Elemente angeliefert werden, bricht die Funktion ab.
#!/usr/bin/perl use strict; use warnings; use feature 'say'; use Finance::QuoteHist; use Math::Business::BlackScholes qw/historical_volatility/; my @symbols = qw/^DJI ^GDAXI/; # Dow Jones and DAX indices my $days_per_year = 252; # Trading days per year # Defaults to Finance::QuoteHist::Yahoo my $q = Finance::QuoteHist->new( symbols => [@symbols], start_date => '30 business days ago', end_date => 'today', ); foreach my $symbol (@symbols) { my @closing_prices; # Iterate over quotes and collect closing prices foreach my $quote ( $q->quotes() ) { my ( $sym, $date, $open, $high, $low, $close, $volume ) = @$quote; next unless $sym eq $symbol; push @closing_prices, $close; } my $days_in_scope = scalar @closing_prices; my $historical_volatility = historical_volatility( \@closing_prices, $days_per_year ); say "Centered historical volatility ($days_in_scope days) for $symbol: $historical_volatility"; }
Das Programm erzeugt z.B. folgende Ausgabe:
Centered historical volatility (30 days) for ^DJI: 0.11825075886597 Centered historical volatility (30 days) for ^GDAXI: 0.147215875305835
Beispiel: Rollende Historische Volatilität
In diesem Beispiel soll die historische Volatilität über die letzten 30 Tradingtage für historische Kursdaten berechnet werden.
Da mindestens 30 Schlusskurse (Array Index 29) zur Berechnung der historischen Volatilität benötigt werden, kann an den ersten 29 Tagen (Array Index von 0 bis 28) keine Vola berechnet werden.
Wie oben bereits erwähnt erwartet historical_volatility() einen genau passenden Array als ersten Parameter. Daher wird die Liste der Schlusskurse, die an historical_volatility() übergeben wird, mittels Array Slices während des Loops über alle Schlusskurse passend erzeugt.
#!/usr/bin/perl use strict; use warnings; use feature 'say'; use Finance::QuoteHist; use Math::Business::BlackScholes qw/historical_volatility/; my @symbols = qw/^DJI ^GDAXI/; # Dow Jones and DAX indices my $days_per_year = 252; # Trading days per year my $days_in_scope = 30; # Defaults to Finance::QuoteHist::Yahoo my $q = Finance::QuoteHist->new( symbols => [@symbols], start_date => '45 business days ago', end_date => 'today', ); foreach my $symbol (@symbols) { # 3 parallel arrays my @closing_prices; my @dates; my @historical_vola; # Iterate over quotes and collect closing prices and dates foreach my $quote ( $q->quotes() ) { my ( $sym, $date, $open, $high, $low, $close, $volume ) = @$quote; next unless $sym eq $symbol; push @closing_prices, $close; push @dates, $date; } # Loop over closing_prices, # slice array @closing_prices to suit historical_volatility() # and collect dates and hist vola for ( my $i = 0 ; $i <= $#closing_prices ; $i++ ) { $historical_vola[$i] = 'N/A'; if ( $i >= $days_in_scope - 1 ) { # Array slice from current index (upper) back down to lookup period (days in scope) -1 (lower) my $lower = $i - ( $days_in_scope - 1 ); my @closing_prices_in_scope = @closing_prices[ $lower .. $i ]; $historical_vola[$i] = historical_volatility( \@closing_prices_in_scope, $days_per_year ); } } # Loop over closing_prices and display index, current symbol, closing price and computed vola for ( my $i = 0 ; $i <= $#closing_prices ; $i++ ) { say "$i $symbol $dates[$i] $closing_prices[$i] $historical_vola[$i]"; } }
Das Programm erzeugt z.B. folgende Ausgabe:
0 ^DJI 2021/06/07 34630.2383 N/A 1 ^DJI 2021/06/08 34599.8203 N/A 2 ^DJI 2021/06/09 34447.1406 N/A 3 ^DJI 2021/06/10 34466.2383 N/A 4 ^DJI 2021/06/11 34479.6016 N/A 5 ^DJI 2021/06/14 34393.7500 N/A 6 ^DJI 2021/06/15 34299.3281 N/A 7 ^DJI 2021/06/16 34033.6719 N/A 8 ^DJI 2021/06/17 33823.4492 N/A 9 ^DJI 2021/06/18 33290.0781 N/A 10 ^DJI 2021/06/21 33876.9688 N/A 11 ^DJI 2021/06/22 33945.5781 N/A 12 ^DJI 2021/06/23 33874.2383 N/A 13 ^DJI 2021/06/24 34196.8203 N/A 14 ^DJI 2021/06/25 34433.8398 N/A 15 ^DJI 2021/06/28 34283.2695 N/A 16 ^DJI 2021/06/29 34292.2891 N/A 17 ^DJI 2021/06/30 34502.5117 N/A 18 ^DJI 2021/07/01 34633.5312 N/A 19 ^DJI 2021/07/02 34786.3516 N/A 20 ^DJI 2021/07/06 34577.3711 N/A 21 ^DJI 2021/07/07 34681.7891 N/A 22 ^DJI 2021/07/08 34421.9297 N/A 23 ^DJI 2021/07/09 34870.1602 N/A 24 ^DJI 2021/07/12 34996.1797 N/A 25 ^DJI 2021/07/13 34888.7891 N/A 26 ^DJI 2021/07/14 34933.2305 N/A 27 ^DJI 2021/07/15 34987.0195 N/A 28 ^DJI 2021/07/16 34687.8516 N/A 29 ^DJI 2021/07/19 33962.0391 0.124834226102961 30 ^DJI 2021/07/20 34511.9883 0.134218934103578 31 ^DJI 2021/07/21 34798.0000 0.135727160336629 32 ^DJI 2021/07/22 34823.3516 0.135730492963977 33 ^DJI 2021/07/23 35061.5508 0.137060882957344 34 ^DJI 2021/07/26 35144.3086 0.136828649663936 35 ^DJI 2021/07/27 35058.5195 0.136761489180455 36 ^DJI 2021/07/28 34930.9297 0.1349734387388 37 ^DJI 2021/07/29 35084.5312 0.133565951288527 38 ^DJI 2021/07/30 34935.4688 0.124188328961976 39 ^DJI 2021/08/02 34838.1602 0.11499320795688 40 ^DJI 2021/08/03 35116.3984 0.116799789157168 41 ^DJI 2021/08/04 34792.6719 0.120453610376238 42 ^DJI 2021/08/05 35064.2500 0.119465773449191 43 ^DJI 2021/08/06 35211.3086 0.118492022837183 0 ^GDAXI 2021/06/07 15677.1504 N/A 1 ^GDAXI 2021/06/08 15640.5996 N/A 2 ^GDAXI 2021/06/09 15581.1396 N/A 3 ^GDAXI 2021/06/10 15571.2197 N/A 4 ^GDAXI 2021/06/11 15693.2695 N/A 5 ^GDAXI 2021/06/14 15673.6396 N/A 6 ^GDAXI 2021/06/15 15729.5195 N/A 7 ^GDAXI 2021/06/16 15710.5703 N/A 8 ^GDAXI 2021/06/17 15727.6699 N/A 9 ^GDAXI 2021/06/18 15448.0400 N/A 10 ^GDAXI 2021/06/21 15603.2402 N/A 11 ^GDAXI 2021/06/22 15636.3301 N/A 12 ^GDAXI 2021/06/23 15456.3896 N/A 13 ^GDAXI 2021/06/24 15589.2305 N/A 14 ^GDAXI 2021/06/25 15607.9697 N/A 15 ^GDAXI 2021/06/28 15554.1797 N/A 16 ^GDAXI 2021/06/29 15690.5898 N/A 17 ^GDAXI 2021/06/30 15531.0400 N/A 18 ^GDAXI 2021/07/01 15603.8096 N/A 19 ^GDAXI 2021/07/02 15650.0898 N/A 20 ^GDAXI 2021/07/05 15661.9697 N/A 21 ^GDAXI 2021/07/06 15511.3799 N/A 22 ^GDAXI 2021/07/07 15692.7100 N/A 23 ^GDAXI 2021/07/08 15420.6396 N/A 24 ^GDAXI 2021/07/09 15687.9297 N/A 25 ^GDAXI 2021/07/12 15790.5098 N/A 26 ^GDAXI 2021/07/13 15789.6396 N/A 27 ^GDAXI 2021/07/14 15788.9805 N/A 28 ^GDAXI 2021/07/15 15629.6602 N/A 29 ^GDAXI 2021/07/16 15540.3096 0.132886029847589 30 ^GDAXI 2021/07/19 15133.2002 0.153747543860939 31 ^GDAXI 2021/07/20 15216.2695 0.154727885312354 32 ^GDAXI 2021/07/21 15422.5000 0.160355346073778 33 ^GDAXI 2021/07/22 15514.5400 0.159598602711704 34 ^GDAXI 2021/07/23 15669.2900 0.162434221185135 35 ^GDAXI 2021/07/26 15618.9805 0.162322368614483 36 ^GDAXI 2021/07/27 15519.1299 0.163323138451846 37 ^GDAXI 2021/07/28 15570.3604 0.163636303169993 38 ^GDAXI 2021/07/29 15640.4697 0.155067342214758 39 ^GDAXI 2021/07/30 15544.3896 0.153399408966577 40 ^GDAXI 2021/08/02 15568.7305 0.153335017048669 41 ^GDAXI 2021/08/03 15555.0801 0.149352162877445 42 ^GDAXI 2021/08/04 15692.1299 0.149461080971496 43 ^GDAXI 2021/08/05 15744.6699 0.149719787680581 44 ^GDAXI 2021/08/06 15778.0996 0.149363427544281
Siehe auch
- Math::Business::BlackScholes - Black-Scholes option price model functions
- Gabler Banklexikon: historische Volatilität
- Ideas Magazin - Volatilität: Definition und Erklärung
- Wikipedia - Volatilität
- Wikipedia (en) - Volatility (finance)
- Historical Volatility Calculator
Source-Code der Beispiele im Github Repo perl-howto-code.