Programmation AS3

Samedi 18 avril 2009 6 18 /04 /Avr /2009 18:11

Voici l'implémentation du modèle binomial. L'arbre recombinant fait l'objet d'une procédure itérative calibrée pour converger vers le modèle de Black&Scholes pour un pas de 160 environ.

package fx.bidesign.maths
{
    import fx.bidesign.maths.Combination;
    import fx.bidesign.maths.ProbabilityTools;

    public class CoxRossRubinstein
    {

        public function CoxRossRubinstein()
        {

        }
        // (sous-jacent, prix d'exercice, jours restant, volatilté, taux sans risque, dividende, parité)
        public static function value( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, steps:Number, p:Number = 1 ):Array
        {
            t = t / steps;
            // 1 - q = ( u - Math.exp( ( r - c ) * t ) ) / ( u - d )
            var d:Number = Math.exp( - v * Math.sqrt( t ) );
            var u:Number = Math.exp( v * Math.sqrt( t ) );
            var q:Number = ( Math.exp( ( r - c ) * t ) - d ) / ( u - d );
           
            var call:Number = 0;
           
            for( var i:int = 0; i < steps + 1; i++ )
            {
                call += Combination.evaluate( steps, i ) * Math.pow( q, i ) * Math.pow( 1 - q, steps - i ) * Math.max( s * Math.pow( u, i ) * Math.pow( d, steps - i ) - k, 0 );
            }
           
            var put:Number = 0;
           
            for( var j:int = 0; j < steps + 1; j++ )
            {
                put += Combination.evaluate( steps, j ) * Math.pow( q, j ) * Math.pow( 1 - q, steps - j ) * Math.max( k - ( s * Math.pow( u, j ) * Math.pow( d, steps - j ) ), 0 );
            }

            return [call / p, put / p ];
        }
        // (sous-jacent, prix d'exercice, jours restant, volatilté, taux sans risque, dividende, parité)
        public static function delta( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, p:Number = 1 ):Array
        {
            var d1:Number = ( Math.log( s / k ) + ( r + Math.pow( v, 2 ) / 2 ) * t ) / ( v * Math.sqrt( t ) );
            var d2:Number = d1 - ( v * Math.sqrt( t ) );

            var call:Number = Math.exp( -  c * t) * ProbabilityTools.normalDistribution( d1 );
            var put:Number = Math.exp( - c * t ) * ( ProbabilityTools.normalDistribution( d1 ) - 1 );

            return [call * 100, put * 100];
        }
        // (sous-jacent, prix d'exercice, jours restant, volatilté, taux sans risque, dividende, parité)
        public static function gamma( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, p:Number = 1 ):Array
        {
            var d1:Number = ( Math.log( s / k ) + ( r + Math.pow( v, 2 ) / 2 ) * t ) / ( v * Math.sqrt( t ) );
            var d2:Number = d1 - ( v * Math.sqrt( t ) );

            var call:Number = Math.exp( - c * t ) * ( ProbabilityTools.normalDensity( d1 ) / ( s * v * Math.sqrt( t ) ) );
            var put:Number = call;

            return [call / ( p / 100 ), put / ( p / 100 )];
        }
        // (sous-jacent, prix d'exercice, jours restant, volatilté, taux sans risque, dividende, prime du put ou du call, parité)
        public static function theta( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, fv:Number, p:Number = 1 ):Array
        {
            var d1:Number = ( Math.log( s / k ) + ( r + Math.pow( v, 2 ) / 2 ) * t ) / ( v * Math.sqrt( t ) );
            var d2:Number = d1 - ( v * Math.sqrt( t ) );
    
            var call:Number = - Math.exp( - c * t ) * s * ProbabilityTools.normalDensity( d1 ) * v / ( 2 * Math.sqrt( t ) );
            call += - r * k * Math.exp( - r * t ) * ProbabilityTools.normalDistribution( d2 );
            call += c * s * Math.exp( - c * t ) * ProbabilityTools.normalDistribution( d1 );
           
            var put:Number = - ( s * Math.exp( - c * t ) * v ) / ( 2 * Math.sqrt( t ) ) * ProbabilityTools.normalDensity( d1 );
            put += + r * k * Math.exp( -r * t ) * ( 1 - ProbabilityTools.normalDistribution( d2 ) );
            put += - c * s * Math.exp( - c * t) * ProbabilityTools.normalDistribution( 1 - d1 );
            return [call / 52 / fv * 100, put / 52 / fv * 100];
        }
        // (sous-jacent, prix d'exercice, jours restant, volatilté, taux sans risque, dividende, prime du put ou du call, parité)
        public static function rho( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, fv:Number, p:Number = 1 ):Array
        {
            var d1:Number = ( Math.log( s / k ) + ( r + Math.pow( v, 2 ) / 2 ) * t ) / ( v * Math.sqrt( t ) );
            var d2:Number = d1 - ( v * Math.sqrt( t ) );

            var call:Number = k * t * Math.exp( - r * t ) * ProbabilityTools.normalDistribution( d2 );
            var put:Number = k * t * Math.exp( - r * t ) * ( ProbabilityTools.normalDistribution( d2 ) - 1 );

            return [call / fv, put / fv];
        }
        // (sous-jacent, prix d'exercice, jours restant, volatilté, taux sans risque, dividende, prime du put ou du call, parité)
        public static function vega( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, fv:Number, p:Number = 1 ):Array
        {
            var d1:Number = ( Math.log( s / k ) + ( r + Math.pow( v, 2 ) / 2 ) * t ) / ( v * Math.sqrt( t ) );
            var d2:Number = d1 - ( v * Math.sqrt( t ) );

            var call:Number = s * Math.exp(- c * t ) * ProbabilityTools.normalDensity( d1 ) * Math.sqrt( t );
            var put:Number = call;

            return [call / fv, put / fv];
        }
        // (sous-jacent, valeur du delta, prime du put ou du call)
        public static function elasticity( s:Number, del:Number, fv:Number ):Array
        {
            var call:Number = s * del / fv;
            var put:Number = s * del / fv;

            return [call / 100, put / 100];
        }
    }
}


Les grecs sont calculés sur le modèle de Black&Scholes mais à l'occasion je mettrais à jour la classe avec les grecs binomiaux. Le pricer sera également mis à jour pour prendre en charge le modèle binomial.

Par Gilles De Truchis - Publié dans : Programmation AS3
Ecrire un commentaire - Voir les 0 commentaires
Samedi 18 avril 2009 6 18 /04 /Avr /2009 12:38

Après avoir présenté le modèle de Black, Scholes et Merton, et avoir proposé une implémentation du modèle, voici une application flash utilisant les classes précédemment mises en ligne. Vous remarquerez qu'elles diffèrent légèrement du modèle formalisé puisque, d'un part on a ajouté la parité, et d'autre part, on a calibré l'application sur les warrants et les pricer de warrant en ligne tel que ceux de Boursorama ou Fortunéo. Les valeurs des grecs ne sont pas toujours identiques car selon les pratiques, certains pricer ramènent le theta en variations hebdomadaires ou journalières par exemple. Cette application comprend également un petit convertisseur de date afin de faciliter le calcul du "Time to Maturity". Voici la classe en question:


package fx.bidesign.utils
{
    
    public class DateConverter
    {
        public function DateConverter()
        {
           
        }
        // cDate = [dd, mm, yyyy]
        public static function evaluate( cDate:Array, mDate:Array ):Number
        {
            var beg:Date = new Date( Number( cDate[2] ), Number( cDate[1] ) - 1, Number( cDate[0] ) );
           
            var end:Date = new Date( Number( mDate[2] ), Number( mDate[1] ) - 1, Number( mDate[0] ) );
           
            var pitch:Number = Math.floor( ( end.getTime() - beg.getTime() ) / 1000 / 3600 / 24 );
           
            return pitch;
        }
    }
}


Vous trouverez également dans les sources, une classe pour pricer des contrats Forward, toujours pour des sous-jacents type action:

package fx.bidesign.maths
{
    import fx.bidesign.maths.Factorial;
    
    public class Forward
    {

        public function Forward()
        {

        }
        public static function evaluate( k:Number, s:Number, r:Number, t:Number, q:Number ):Array
        {
            var f1:Number = s * Math.exp( - q * t ) * Math.exp( r * t );
            var f2:Number = ( f1 - k ) * Math.exp( - r * t );
           
            return [f1, f2];
        }
    }
}



Et voici le pricer:

Par Gilles De Truchis - Publié dans : Programmation AS3
Ecrire un commentaire - Voir les 0 commentaires
Samedi 18 avril 2009 6 18 /04 /Avr /2009 12:18

J'ai enfin trouvé le temps de recoder mes classes financières et je mets donc en ligne la classe Black&Scholes avec en plus les méthodes statiques pour les grecs.

package fx.bidesign.maths
{
    import fx.bidesign.maths.ProbabilityTools;

    public class BlackScholes
    {

        public function BlackScholes()
        {

        }
        // (sous-jacent, prix d'exercice, jours restant, volatilté, taux sans risque, dividende, parité)
        public static function value( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, p:Number = 1 ):Array
        {
            var d1:Number = ( Math.log( s / k ) + ( r + Math.pow( v, 2 ) / 2 ) * t ) / ( v * Math.sqrt( t ) );
            var d2:Number = d1 - ( v * Math.sqrt( t ) );

            var call:Number = s * Math.exp( - c * t ) * ProbabilityTools.normalDistribution( d1 ) - k * Math.exp( - r * t ) * ProbabilityTools.normalDistribution( d2 );
            var put:Number = - s * Math.exp( - c * t ) * ProbabilityTools.normalDistribution( - d1 ) + k * Math.exp( - r * t ) * ProbabilityTools.normalDistribution( - d2 );

            return [call / p, put / p ];
        }
        // (sous-jacent, prix d'exercice, jours restant, volatilté, taux sans risque, dividende, parité)
        public static function delta( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, p:Number = 1 ):Array
        {
            var d1:Number = ( Math.log( s / k ) + ( r + Math.pow( v, 2 ) / 2 ) * t ) / ( v * Math.sqrt( t ) );
            var d2:Number = d1 - ( v * Math.sqrt( t ) );

            var call:Number = Math.exp( -  c * t) * ProbabilityTools.normalDistribution( d1 );
            var put:Number = Math.exp( - c * t ) * ( ProbabilityTools.normalDistribution( d1 ) - 1 );

            return [call * 100, put * 100];
        }
        // (sous-jacent, prix d'exercice, jours restant, volatilté, taux sans risque, dividende, parité)
        public static function gamma( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, p:Number = 1 ):Array
        {
            var d1:Number = ( Math.log( s / k ) + ( r + Math.pow( v, 2 ) / 2 ) * t ) / ( v * Math.sqrt( t ) );
            var d2:Number = d1 - ( v * Math.sqrt( t ) );

            var call:Number = Math.exp( - c * t ) * ( ProbabilityTools.normalDensity( d1 ) / ( s * v * Math.sqrt( t ) ) );
            var put:Number = call;

            return [call / ( p / 100 ), put / ( p / 100 )];
        }
        // (sous-jacent, prix d'exercice, jours restant, volatilté, taux sans risque, dividende, prime du put ou du call, parité)
        public static function theta( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, fv:Number, p:Number = 1 ):Array
        {
            var d1:Number = ( Math.log( s / k ) + ( r + Math.pow( v, 2 ) / 2 ) * t ) / ( v * Math.sqrt( t ) );
            var d2:Number = d1 - ( v * Math.sqrt( t ) );
    
            var call:Number = - Math.exp( - c * t ) * s * ProbabilityTools.normalDensity( d1 ) * v / ( 2 * Math.sqrt( t ) );
            call += - r * k * Math.exp( - r * t ) * ProbabilityTools.normalDistribution( d2 );
            call += c * s * Math.exp( - c * t ) * ProbabilityTools.normalDistribution( d1 );
           
            var put:Number = - ( s * Math.exp( - c * t ) * v ) / ( 2 * Math.sqrt( t ) ) * ProbabilityTools.normalDensity( d1 );
            put += + r * k * Math.exp( -r * t ) * ( 1 - ProbabilityTools.normalDistribution( d2 ) );
            put += - c * s * Math.exp( - c * t) * ProbabilityTools.normalDistribution( 1 - d1 );
            return [call / 52 / fv * 100, put / 52 / fv * 100];
        }
        // (sous-jacent, prix d'exercice, jours restant, volatilté, taux sans risque, dividende, prime du put ou du call, parité)
        public static function rho( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, fv:Number, p:Number = 1 ):Array
        {
            var d1:Number = ( Math.log( s / k ) + ( r + Math.pow( v, 2 ) / 2 ) * t ) / ( v * Math.sqrt( t ) );
            var d2:Number = d1 - ( v * Math.sqrt( t ) );

            var call:Number = k * t * Math.exp( - r * t ) * ProbabilityTools.normalDistribution( d2 );
            var put:Number = k * t * Math.exp( - r * t ) * ( ProbabilityTools.normalDistribution( d2 ) - 1 );

            return [call / fv, put / fv];
        }
        // (sous-jacent, prix d'exercice, jours restant, volatilté, taux sans risque, dividende, prime du put ou du call, parité)
        public static function vega( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, fv:Number, p:Number = 1 ):Array
        {
            var d1:Number = ( Math.log( s / k ) + ( r + Math.pow( v, 2 ) / 2 ) * t ) / ( v * Math.sqrt( t ) );
            var d2:Number = d1 - ( v * Math.sqrt( t ) );

            var call:Number = s * Math.exp(- c * t ) * ProbabilityTools.normalDensity( d1 ) * Math.sqrt( t );
            var put:Number = call;

            return [call / fv, put / fv];
        }
        // (sous-jacent, valeur du delta, prime du put ou du call)
        public static function elasticity( s:Number, del:Number, fv:Number ):Array
        {
            var call:Number = s * del / fv;
            var put:Number = s * del / fv;

            return [call / 100, put / 100];
        }
    }
}


Cette classe appartient au package fx.bidesign.maths. Les sources seront mises à dispositions lorsques l'ensemble des tutoriaux concernant le pricer seront publiés

Par Gilles De Truchis - Publié dans : Programmation AS3
Ecrire un commentaire - Voir les 0 commentaires
Dimanche 5 avril 2009 7 05 /04 /Avr /2009 15:29

Qu'il me soit permis de m'éloigner un peu de la finance et de présenter, dans un registre bien plus léger, un tutoriel sur l'utilisation des nouvelles fonctionnalités de la classe Sound sous le flash player 10.

Les développeurs AS3 que vous êtes auront bien-sûr constaté que la classe Sound diffuse, depuis la sortie de flash player 10, un nouvel événement: SampleData. Cet événement est distribué lorsque le lecteur demande de nouvelles données audio et permet de gérer le son généré dynamiquement ou lu. Dans cet environnement, l'objet Sound ne contient pas vraiment de données audio. Il agit en fait en tant que socket pour les données audio qui lui sont distribuées en continu par l'intermédiaire de la fonction écouteur. On va ainsi être en mesure de collecter, via des BytesArray, des échantillons du son généré ou lu. Le flash player 10 inclus parmi ses nouveautés une nouvelle fonctionnalité qui manquait cruellement aux anciennes versions: la méthode FileReference.save( data:*, defaultFileName:String = null). Les données collectées, qui en cet instant sont au format RAW (Real Audio Wrapper), vont alors pouvoir être encodées puis écrites en dur, via cette méthode, sur le disque. Pour plus de précision sur le format des données, on pourra se tourner vers les PCM (Modulation d'impulsion codée). Enfin présentons la méthode star de ce tutoriel: Sound.extract(target:ByteArray, length:Number, startPosition:Number = -1):Number. Cette méthode doit être employée lorsque l'on gére un son généré dynamiquement ou lu, à l'aide d'une fonction que l'on affecte à l'événement SampleData pour un autre objet Sound. En d'autres termes, on va utiliser cette méthode pour extraire les données audio d'un objet Sound. Le flash player autorise un fourchette pour le nombre d'échantillons à fournir: [2048, 8192]. La qualité sera bien-sûr maximal avec 8192.


Pour commencer, nous allons déclarer les objets dont nous avons besoins:


var sound:Sound = new Sound();
var dynamicSound:Sound = new Sound();
var soundChannel:SoundChannel = new SoundChannel();
var samples:ByteArray = new ByteArray();
var sndBytes:ByteArray = new ByteArray();
var myFileRefSave:FileReference = new FileReference();


Sur la scène nous disposons de 2 boutons, l'un de label "Record" et d'occurence "record" sert à lancer le son et collecter les échantillons et l'autre de label "Save" et d'occurence "save" sert à appeler la méthode save de FileReference.


record.addEventListener( MouseEvent.MOUSE_DOWN, startRecord );

function startRecord( pEvt:MouseEvent )
{
    sound = new Track();
   
    dynamicSound.addEventListener( SampleDataEvent.SAMPLE_DATA, sampleData );
    soundChannel = dynamicSound.play();
   
    save.addEventListener( MouseEvent.MOUSE_DOWN, stopRecord );
}

function sampleData( pEvt:SampleDataEvent ):void
{
    samples.position = 0;
   
    var len:Number = sound.extract( samples, 8192 );
   
    var left:Number;
    var right:Number;
   
    samples.position = 0;
   
    sndBytes.writeBytes( samples );
   
    for ( var c:int=0; c < len; c++ )
    {
        left = samples.readFloat();
        right = samples.readFloat();
       
        pEvt.data.writeFloat( left );
        pEvt.data.writeFloat( right );
    }
}

function stopRecord( pEvt:MouseEvent )
{
    myFileRefSave.save( FxWaveEncoder.encoder( sndBytes ), "snd.wav" );
}


Notons que Track est le nom de classe (ou liaison pour les anciens d'AS2) d'un son placé dans la librairie.
Avant d'être écrit on converti le son via la méthode static:
FxWaveEncoder.encoder( pSamples:ByteArray, channels:int = 2, bits:int = 16, rate:int = 44100 ):ByteArray

Voici la classe FxWaveEncoder qui permet d'encoder le format. Je remercie les membres de Médiabox qui m'ont aidé à calibrer cette classe:


package
{
    import flash.utils.Endian;
    import flash.utils.ByteArray;
   
    import flash.events.Event;

    public class FxWaveEncoder
    {
       
        // writeHeader ( 2, 16, 44100 )
        static public function encoder( pSamples:ByteArray, channels:int = 2, bits:int = 16, rate:int = 44100 ):ByteArray
        {
            var samples:ByteArray = new ByteArray();
           
            samples.writeBytes( FxWaveEncoder.convert( pSamples ) );
           
            var bytes: ByteArray = new ByteArray();
           
            bytes.endian = Endian.LITTLE_ENDIAN;
           
            bytes.writeUTFBytes( 'RIFF' );
           
            bytes.writeInt( samples.length - 8 );
           
            bytes.writeUTFBytes( 'WAVE' );
           
            bytes.writeUTFBytes( 'fmt ' );
           
            bytes.writeInt( int( 16 ) );
           
            bytes.writeShort( int( 1 ) );
           
            bytes.writeShort( channels );
           
            bytes.writeInt( rate );
           
            bytes.writeInt( int( rate * channels * ( bits / 8 ) ) );
           
            bytes.writeShort( int( channels * ( bits / 8 ) ) );
           
            bytes.writeShort( bits );
           
            bytes.writeUTFBytes( 'data' );
           
            bytes.writeInt( samples.length - 44 );
           
            bytes.writeBytes( samples );
           
            bytes.position = 0;
           
            return bytes;
        }
        static private function convert( pBytes:ByteArray ):ByteArray
        {
            var ba:ByteArray = new ByteArray ( ) ;
           
            ba.endian = Endian.LITTLE_ENDIAN;
           
            pBytes.position = 0;
           
            while( pBytes.position < pBytes.length ) ba.writeShort( pBytes.readFloat() * 32767 );
           
            return ba;
        }
    }
}


Pour les détails des chunks on pourra se référer aux liens de bas de page de cette article: WAVE
Ce n'est pas très sexy mais bien pratique.

Et voici le résultat:

Par Gilles De Truchis - Publié dans : Programmation AS3
Ecrire un commentaire - Voir les 0 commentaires
Samedi 28 février 2009 6 28 /02 /Fév /2009 23:47

Avant d'attaquer les greeks voici la classe BlackScholes qui prend donc comme paramètre le spot, le strike price, taux sans risque, la maturité, la volatilité, le dividende et la maturité dont nous aurons l'occasion de reparler.

package fx.bidesign.maths
{
    import fx.bidesign.maths.ProbabilityTools;

    public class BlackScholes
    {

        public function BlackScholes()
        {

        }
        public static function value( s:Number, k:Number, t:Number, v:Number, r:Number, c:Number, p:Number = 1 ):Array
        {
            var d1:Number = ( Math.log( s / k ) + ( r + Math.pow( v, 2 ) / 2 ) * t ) / ( v * Math.sqrt( t ) );
            var d2:Number = d1 - ( v * Math.sqrt( t ) );

            var call:Number = s * Math.exp( - c * t ) * ProbabilityTools.normalDistribution( d1 ) - k * Math.exp( - r * t ) * ProbabilityTools.normalDistribution( d2 );
            var put:Number = - s * Math.exp( - c * t ) * ProbabilityTools.normalDistribution( - d1 ) + k * Math.exp( - r * t ) * ProbabilityTools.normalDistribution( - d2 );

            return [call / p, put / p ];
        }
    }
}

Cette classe appartient au package fx.bidesign.maths. Les sources seront mises à dispositions lorsques l'ensemble des tutoriaux concernant le pricer seront publiés

Par Gilles De Truchis - Publié dans : Programmation AS3
Ecrire un commentaire - Voir les 0 commentaires

Un problème d'affichage...?

Certaines pages de ce site contiennent des animations Flash qui nécessitent la dernière version du flash player.

haut de page

Varennes EcoFin

Mon site internet migre vers une nouvelle adresse: Varennes EcoFin. Il s'agit d'un site en flash recentré sur mes travaux de recherches, ma thèse et des resources pour les étudiants (programmes, bases de données etc.). Pour accéder à la version sans flash (HTML5): Varennes EcoFin Sky.

Présentation

Recherche

Music Player

 
Créer un blog gratuit sur over-blog.com - Contact - C.G.U. - Signaler un abus - Articles les plus commentés