Assembly code – Exotic option simulation

THIS PROGRAM SIMULATES THE BEHAVIOR OF AN EXOTIC OPTION.

THE PROGRAM ASKS THE USER WHETHER HE PREFERS TO BUY A PUT OR A CALL. SUBSEQUENTLY, IT PRICES THE DERIVATIVE VIA MONTECARLO. A SIMULATED UNDERLYING ASSET TRAJECTORY IS COMPUTED AND SHOWN THE USER. A PAYOFF IS CALCULATED AND THE USER IS FINALLY INFORMED OF THE OUTCOME OF HIS BET.

Il s’agit d’un projet de taille considérable qui reproduit, en code Assembleur, certains des concepts étudiés dans le cadre d’un master en finance quantitative. Je l’ai réalisé dans le but de me familiariser davantage avec la programmation de bas niveau.

Afin de simplifier la complexité du projet, certaines simplifications mathématiques et financières ont été introduites. En particulier, nous utilisons un modèle de Mouvement Brownien Géométrique, alors que des modèles tels que celui de Black et Scholes seraient plus appropriés. Les propriétés de la distribution gaussienne, avec une variance quotidienne, ainsi que la méthode de calcul pour actualiser le prix final, sont également simplifiées.

Le code source est déposé à https://github.com/giosds/giasm

our le développement, l’interpréteur 8088 a été utilisé, Assembler and Tracer Toolkit: https://github.com/StoDevX/as88

Più sotto, in lingua inglese, è riportata la documentazione presente all’interno del codice.

Ci-dessous, en anglais, se trouve la documentation trouvée dans le code.

Caractéristiques principales :

  • Génération de nombres pseudo-aléatoires, avec une séquence différente à chaque exécution.
  • Tarification d’une option à double barrière à l’aide d’une simulation de Monte Carlo.
  • Représentation graphique animée de la méthode de Monte Carlo.
  • Génération du chemin aléatoire de l’actif sous-jacent hypothétique et communication à l’utilisateur du profit ou de la perte généré par un contrat dérivé.
  • Graphiques de console textuelle.
  • Plusieurs limitations dues à l’architecture utilisée, notamment : aucune opération arithmétique en virgule flottante n’est possible (seulement en entier), les registres sont de 16 bits, et seules 7 appels de bibliothèque système sont disponibles.
  • Chaque élément du programme est paramétré. Pour des raisons de calcul ou autres (par exemple, rendre certaines composantes absolues ou relatives les unes par rapport aux autres), les paramètres financiers subissent certaines manipulations dans certains cas, qui sont gérées par l’algorithme

 

Le premier fichier appelle les fonctions nécessaires qui se trouvent dans d’autres fichiers liés.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<pre>#include "consts.h"    !
#include "usrPrms.h"    !

!   THIS PROGRAM SIMULATES THE BEHAVIOR OF AN EXOTIC OPTION.

!   -----------------------------------------------------------------
!   PROGRAM:
!   THE PROGRAM ASKS THE USER WHETHER HE PREFERS TO BUY A PUT OR A CALL.
!   SUBSEQUENTLY, IT PRICES THE DERIVATIVE VIA MONTECARLO. 
!   A SIMULATED UNDERLYING ASSET TRAJECTORY IS COMPUTED AND SHOWN THE USER.
!   A PAYOFF IS CALCULATED AND THE USER IS FINALLY INFORMED OF THE OUTCOME OF HIS BET.

!   -----------------------------------------------------------------
!   OPTION BEHAVIOR:
!   THE OPTION PAYS THE DIFFERENCE BETWEEN THE UNDERLYING ASSET
!   AND THE STRIKE IF IT IS IN THE MONEY, ZERO OTHERWISE.
!   THERE ARE TWO KNOCK-OUT BARRIERS, A CAP AND A FLOOR: IF THE ASSET
!   REACHES A BARRIER, THE PRICE IS FIXED UNTIL EXPIRATION.

!   -----------------------------------------------------------------
!   PROGRAM DESCRIPTION:
!   Whenever possible, multiplications are done before divisions, in order
!       to contain remainder approximations.
!
!   The user helps generating 3 initial numbers by keeping the Enter key pressed
!       for a while (too small a time is not allowed).
!   The lowest binary digits of those initial numbers form the basis for new numbers.
!   Three different combinations of those basis are assembled to form 3 different numbers,
!       which   are less predictable than the original ones.
!   These new numbers are 3 random seeds for 3 Linear Congruential Generators.
!   Three sequences are thus generated: they contain uniform pseudo-random variables.
!   The 3 sequences interact to generate one longer-period sequence (still uniforms).
!       This one is used as a source of randomness for all the simulations.
!   Next: 48 uniform variables are used at a time to yeld an approximated gaussian-distributed
!       random variable, relying on the Central Limit theorem.
!       The number 48 is a convenient number, it being: 2 squared, times 12.
!       Still, it produces better gaussians than 12.
!       12 is related to the uniform distribution standard deviation; 4 saves us a square-root computation,
!       which   would complicate matters in an environment where floating-point arithmetic is not available.
!   The gaussian variable is appropriately standardized and scaled (the values must fit in the registers)
!       and used to form a Geometric Brownian Motion for the prices of the asset.
!   Then barriers are applied, limiting the asset prices.
!   A payoff is computed, relative to a strike price.
!   Using Montecarlo, many payoffs are averaged and discounted to price the derivative.
!   Some of the asset trajectories are shown in an animated plot, in the text-based console.
!   Prices are scaled and matched to a row number. If the columns allowed are fewer than
!       the whole trajectory, the plot is split into as many parts as needed.
!       The trajectory is rescaled for every example, so that each time the maximum and
!       minimum values are placed on the upper and lower rows of the plot.
!   The strike price is shown as a heavy line: ======

!   -----------------------------------------------------------------
!   PARAMETERS FOR THE PROGRAM
!  
!   USER MODIFIABLE PARAMETERS [usrPrms.h] file:
!   The first section of the file contains the parameters that determine the
!   asset trajectory in time and the behavior of the derivative. The user can modify them.
!   _days: the number of days the simulation will cover. E.g. Tn = 252
!   _startPr: price of the asset in T0. It is also the basis for other transformations.
!                   20000 performs better in divisions (smaller remainders), 10000 is nicer
!   _bpDrift: drift of the asset, expressed in basis points, relative to the prices of the GBM
!   _bpReqStd: the standard deviation which the simulator is required to generate for the asset
!   _put: whether the option is a put or a call
!   _strike: the strike price
!   _cap: the upper barrier
!   _floor: the lower barrier
!
!   DEBUG AND PROGRAM:
!   Parameters used for debugging and fine-tuning the program.
!   _nRows, _nCols: rows and columns to display the plot.
! _dbgSd1, _dbgSd2, _dbgSd3: random seeds used to bypass the user-generation section.
!
!   CONSTANTS [consts.h] file:
!   This file should need no modifications.
!   It is worth mentioning the LOOPS part. Two variables are used to overcome the 16-bit constraint
!   on the CX register.
!   _hMcCount * _lMcCount is the number of trajectories Montecarlo runs on.
!   NOP1 * NOP2 is the number of cycles the program skips between the demonstrative plots.

!   =================================================================
!   This file, [main.s], contains the main part of the program:
!       - Computes some useful math initializations
!       - If the debug flag is on, assigns values and skip parts
!       Otherwise:
!       - Requires the user to generate 3 numbers as time spans
!       - Assembles the numbers into seeds
!               the seeds are used to initialize the random sequences
!               every sequence generation updates the seeds with the last generated element
!       - Runs Montecarlo and stores the payoff
!           Also plots the first MAXMCPLT sequences, inserting NOPs to let the user see them
!       - Computes one last trajetory and plots it

!   -----------------------------------------------------------------
! ASSEMBLE AS:
!   ./as88 main prFuncs series genrand vars mtCarlo prTraj
! GOOD VALUES: _days:252, rows 30, cols 100


.SECT .TEXT        
   
! PERFORM SOME INITIALIZATIONS
    CALL initVars  
! CHECK DEBUG
    JMP dbgChk1 ! If debug flag is on, set some values and jump to dbg1
    noDbg1:
! INFORM THE USER ABOUT THE PARAMETERS
    CALL prInfo1
    CALL pause
   
! ASK THE USER WHETHER PUT OR CALL
    CALL askPut
    CALL pause
    CALL pause
   




! ASK USER TO GENERATE SEED COMPONENTS

    CALL get3nums                                   !   User generates 3 ints pressing Enter for some time (genrand.s)
   
! BUILD SEEDS
    CALL getSeeds                                   !   User ints are converted into better numbers, usable as seeds (genrand.s):
                                                                    !           user numbers are shifted to keep 3 modulo values, used as
                                                                    !           bases of different order. They are switched in 3 combinations
                                                                    !           to get 3 different seeds.

! RUN A MONTECARLO EXPERIMENT  
dbg1:
    PUSH (hMcCount)                             !   Higherpart of the counter Should not overflow 3*32000
    PUSH (lMcCount)                             !   Lower part of the counter
    CALL runMc                                          !   Generates one complete Geometric Brownian price trajectory
                                                                    !       Also plots the first trajectories (mtCarlo.s)
    ADD SP,4
    MOV AX, (mcPayOff)
    CALL dscnt
    MOV (dscPayOff), AX

! INFORM THE USER ABOUT THE COST
    CALL prInfo2
    CALL pause

! RUN AND PRINT ONE TRAJECTORY
    !CALL runEpr                                        ! Runs a single trajectory and prints the sequences values (mtCarlo.s)
    CALL trjctry
    CALL prInfo3
    CALL pr4Seq                                     !   THE LAST RUN OF UNIFORM SEQUENCES
                                                                    !   genfuncs.
    CALL pause
    CALL prInfo4
    CALL prGaSeq                                    !   GAUSSIANS
                                                                    !   genfuncs.s
    CALL pause
    CALL prInfo5
    CALL prGmb                                      ! BROWNIAN MOTION
                                                                    !   genfuncs.s
    CALL pause
    CALL prInfo6
    CALL pause
! PLOT ONE TRAJECTORY
    CALL fullPlot                                       ! Plots the trajectory calculated above
    CALL pause
   
! TELL THE USER THE OUTCOME
    CALL payOff
    CALL tellOutc
    CALL pause
   
    PUSH _EXIT     
    PUSH _EXIT     
    SYS        
   
   
!   -----------------------------------------------------------------
!   DEBUG

dbgChk1:
    CMP (debug), TRUE                               ! Jump if not debugging. Next lines bypass inputs
    JNE noDbg1
    MOV (seed1), _dbgSd1
    MOV (seed2), _dbgSd2
    MOV (seed3), _dbgSd3       
    JMP dbg1</pre>

GÉNÉRATION D’ALÉATOIRE

Les limitations de l’interpréteur ne permettent pas d’accéder à l’horloge système ni à d’autres sources de hasard, il est donc nécessaire d’interagir avec l’utilisateur.

  • L’utilisateur est invité à maintenir la touche Entrée enfoncée pendant un certain temps, puis à appuyer sur une touche différente. Un certain nombre de caractères (‘\n’) sont ainsi générés et comptés. Pour rendre l’interaction plus réaliste, une pression trop courte réinitialise le comptage. Bien sûr, il serait possible de compter les pressions individuelles sur Entrée, mais il ne s’agit pas d’une application cryptographique…
  • Trois nombres sont générés comme décrit ci-dessus. Les 4 bits de poids faible (correspondant à MOD 16, moins gérables par l’utilisateur) sont conservés pour chacun des 3 nombres. Ils sont ensuite reconstitués dans différentes combinaisons possibles afin de créer 3 nouveaux nombres de 12 bits, indépendamment de la durée des pressions sur Entrée. Ceux-ci sont les valeurs initiales qui alimentent l’algorithme de génération de nombres aléatoires.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
<pre>! THIS MODULE GENERATES RANDOMNESS
! The getnum function returns a random value
! Prints messages. User is asked to press key in order
! to generate one component of a random seed.
! Returns seed in AX

.SECT .TEXT    
           
!   -----------------------------------------------------------------
! BUILD SEEDS
! Builds 3 random seeds using the 3 components
! Seeds vary between [0, 4367]
getSeeds:                      
                                       
    PUSH BP
    MOV  BP,SP                                         
       
    PUSH (chaos1)                                   ! Compute seed 1
    PUSH (chaos2)
    PUSH (chaos3)
    CALL getSeed
    MOV (seed1), AX                             ! Store seed1 in memory
   
    PUSH (chaos3)                                   ! Compute seed 2
    PUSH (chaos1)
    PUSH (chaos2)
    CALL getSeed
    MOV (seed2), AX                             ! Store seed2 in memory
   
    PUSH (chaos2)                                   ! Compute seed 3
    PUSH (chaos3)
    PUSH (chaos1)
    CALL getSeed
    MOV (seed3), AX                             ! Store seed3 in memory
   
! PRINT SEEDS
    MOV AX, step
    MOV DX,(seed1)
    CALL prnt_msg
    MOV AX, step
    MOV DX,(seed2)
    CALL prnt_msg
    MOV AX, step
    MOV DX,(seed3)
    CALL prnt_msg
   
    MOV SP,BP                  
    POP BP
    RET

!   -----------------------------------------------------------------
!   ASK USER TO GENERATE 3 NUMBERS
get3nums:

    PUSH BP
    MOV  BP,SP     
    PUSH BX
    PUSH DI
   
   
    MOV AX,msg1                                     ! Msg to user
    CALL prnt_msg
    MOV BX,0
    MOV CX, (lp_chaos)                          ! Times the input is asked
    MOV DI,chaos3                                   ! 3rd seed component

1:MOV AX, step                                      !Msg to user
    MOV DX,CX                                           !    Num value for print (loop n. CX)
    CALL prnt_msg
    CALL getNum                                     ! Get random seed: prompt msg to user
                                                                    !       collects input, returns rnd seed [0,9]
                                                                    !       uses BX to generate seed (seed accumulator)                                    
    STOS                                                        ! Store seed in AX to DI variable, then increment DI
    MOV BX,0                                                ! Reset seed accumulator
    LOOP 1b                                             ! More input asked for

    POP DI                                                  ! Reset state
    POP BX
    MOV SP,BP                  
    POP BP
    RET

getNum:                            
    PUSH BP
    MOV  BP,SP                 
    PUSH BX                                             ! Save state
   
    MOV AX, prompt_ms                           ! Print message
    CALL prnt_msg                                   ! =
    CALL pause                                          ! Wait
    PUSH _GETCHAR                               ! =
    CALL  cls                                               ! Clear screen (azzera AL)
   
1:                                                              ! Enter-reading loop
    INC BX                                                  ! Increment counter
    SYS                                                     ! Get char
    CMPB AL,'\n'               
    JE 1b                                                       ! If Enter, continues loop.
   
rd:SYS                                                      ! Clears possible extra chars
    CMPB AL,'\n'                                        ! =
    JNE rd                                                  ! =
   
    CMP BX, (n_chars)                               ! If not Enter, tries to exit loop: if BX below n_chars stays in, otherwise exits loop
    JLE k_psh                                               ! If below threshold: prints message, decreases counter, loops back to 1
    CALL  cls                                               ! Exit conditions satisfied:  exit getNum function
    AND BX, 0XF                                     ! Only keeps the last 4 bits, yelding mod 16
   
    MOV AX,BX                                           ! Return value in register AX

                                                                    ! Reset state
    POP BX
    MOV SP,BP                                           ! Clear stack
    POP BP
    RET
!   -----------------------------------------------------------------
! PRINTS "KEEP PUSHING" if release is too quick
k_psh:
    PUSH BP                    
    MOV BP,SP
    SUB BX, (bck_chars)                         ! Decrements counter
    PUSH k_push             ! Prints 'keep pushing'
    PUSH _PRINTF
    SYS
    PUSH _GETCHAR
    SYS
    CALL  cls
    MOV SP,BP
    POP BP
    JMP 1b                                                  ! Back to loop


!   -----------------------------------------------------------------
!   GET ONE SEED OUT OF THREE
!   KEYPRESS COMPONENTS
!   components: number after AND (0-15)

getSeed:                                                    ! needs 3 components on the stack, returns
                                                                    ! seed in AX
    PUSH BP
    MOV BP,SP  
   
! ADD AND SHIFT
! Equivalent to: n1*16*16+n2*16+n3
    MOVB CL,4                  
    MOV AX, 4(BP)                                   ! Use 1st seed component
    SHL AX, CL                 
    ADD AX, 6(BP)                                   ! Use 2nd seed component
    SHL AX, CL
    ADD AX, 8(BP)                                   ! Use 3rd seed component
    MOV SP,BP
    POP BP
    RET 6                                                   ! Clean up the stack
</pre>

À partir des valeurs initiales (les seed), plusieurs séquences sont générées.

  • Trois générateurs congruentiels linéaires créent une série de 48 nombres uniformes.
  • Ces trois séries interagissent pour alimenter les valeurs initiales d’une quatrième série de 48 nombres, qui aura une période plus longue que chacune des précédentes.
  • Une sommation est effectuée sur les 48 nombres, ce qui renvoie une variable aléatoire distribuée selon une loi gaussienne.
  • La variable gaussienne est ensuite standardisée.
  • Dans les opérations précédentes, des difficultés sont rencontrées en raison de la taille limitée des registres (il est nécessaire d’utiliser le débordement) et de l’absence d’arithmétique décimale. Les formules sont adaptées pour résoudre certains problèmes en amont.

 

Le nouveau nombre gaussien sera la composante aléatoire d’un Mouvement Brownien Géométrique. Il s’agit de la trajectoire d’un actif sous-jacent hypothétique. Autant de nombres gaussiens sont générés que d’intervalles dans la période considérée (selon les paramètres fournis : 252 jours).

  • Cette composante gaussienne est modifiée en termes de moyenne et de variance conformément aux paramètres financiers requis (dérive et variance quotidienne).
  • Il est toutefois nécessaire de limiter la plage de ce mouvement brownien pour réduire la complexité arithmétique. C’est pourquoi les barrières sont utiles.
  • Les barrières, cap et floor, lorsqu’elles sont touchées, fixent le prix de l’actif sous-jacent jusqu’à la fin de la période.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
<pre>! The getnum function returns a random value [0-7]
! Prints messages. User is asked to press key in order
! to generate one component of a random seed.
! Returns seed in AX

.SECT .TEXT        

! -------------------------------------------------------------------
!   APPLY BARRIERS
!   Reads in a whole trajectory and applies two knock-out
!   barriers to it.
!   Optimization: the barriers could either be applied where
!       the trajectory is made, or they could just be tested after plotPars.
!       The Apply Barriers step simplifies
!       the code, which is thus more modular.
!
!   NOTE: The option doesnt die when knocked-out.
!       The underlying asset price freezes until expiration.
!       This means that the present value of the payoff
!       will be discounted considering the full period.
!   CALLED: after the gmb call.
!   EXPECTS: nothing - uses global variables for everything,
!       for consistency with functions related to this one
!   ALTERS: CX, AX

applBarr:
    PUSH BP
    MOV BP,SP
    PUSH SI

    MOV SI, brownSeq                                    ! Put brownian sequence in SI
    MOV CX, (days)                                      ! Length of the br. sequence
   
    MOV DX, (floor)                                     ! Down and out level
    MOV AX, (cap)                                           ! Up and out level
   
! LOOK FOR KNOCK OUTS
!   If the price reaches a barrier, enter the next loop.
!   Otherwise jump to return
1:CMP DX, (SI)
    JG 2f                                                           ! Knock out (down)
    CMP AX, (SI)
    JL 2f                                                           ! Knock out (up)
    ADD SI,2
    LOOP 1b
    JMP 4f                                                      ! The loop completed without reaching barriers. Exit
! BARRIER REACHED
!   Continue the previous loop, copying
!   the last price (currently in (SI) ) until expiration
2:MOV DX, (SI)                                          ! Store last price
3:MOV (SI), DX                                          ! Copy last price to the sequence
    ADD SI, 2
    LOOP 3b
    MOV AX, DX
    MOV (lstBrPr), DX
4:
    POP SI
    MOV SP, BP
    POP BP
    RET
   

! -------------------------------------------------------------------
!   GENERATE GEOMETRIC BROWNIAN MOTION
!   EXPECTS price on the stack (AX will be price)
!
!   LAST PRICE IS RETURNED IN AX and saved in lstBrPr
!   ALTERS CX, AX

gbm:
    PUSH BP
    MOV BP,SP
    PUSH DI
    PUSH SI
    PUSH BX
       
    MOV AX, 4(BP)                                       ! Start price
    MOV CX,(days)                                       ! Number of gaussians to generate
    XOR SI,SI
   
gbmLp: 
    MOV DI, gaussSeq(SI)                            ! Take the gaussian
    ADD DI, (drift)                                         ! Add the drift
    CMP DI,0
    JG 1f                                                           ! If positive, branch
    NEG DI                                                      ! NEGATIVE CASE
    MOV BX, AX                                              ! Save price   
    MUL DI                                                      ! Multiply price times (drift+random)
    DIV (basePct)                                           ! Percentify the price movement
    NEG AX                                                      ! Restore negative sign
    ADD AX, BX                                              ! Add the price movement to the price
    XOR DX, DX                                              ! Reset DX
    JMP 2f
   
1:MOV BX, AX                                                ! POSITIVE  CASE
    MUL DI                                                      ! Same as negative, without sign issues
    DIV (basePct)              
    ADD AX, BX             
    XOR DX, DX
   
   
2:MOV brownSeq(SI), AX                          ! Store value in brownian sequence, same position as in gaussian
    ADD SI,2                                                    ! Advance sequences pointer
    LOOP gbmLp                                          ! Continue until days finish
   
    MOV (lstBrPr), AX
    POP BX
    POP SI
    POP DI
    MOV SP,BP
    POP BP         
    RET

!   -----------------------------------------------------------------
! GENERATE AND ADD A GAUSSIAN SEQUENCE
!   The number of gaussian numbers to generate is
!   on the stack
!   Uses global variable gaussCount to keep track of current gaussian being written.

genGaSeq:
    PUSH BP
    MOV  BP,SP
    PUSH DI
   
    MOV CX, 4(BP)                                       ! Get number of gaussians to generate
    XOR DI,DI                                                   ! Set gauss array to 0
1:PUSH CX                                                   ! Save loop state. Will change in genGausN
    MOV (gaussCount),DI                         ! Update counter of generated gaussians
    CALL genGausN                                       ! Generate one gaussian variable
    ADD DI,2                                                    ! Increment destination
    POP CX                                                      ! Retrieve loop state
    LOOP 1b

    POP DI
    MOV  SP,BP
    POP BP
    RET
   
!   -----------------------------------------------------------------
! GENERATE AND ADD A GAUSSIAN NUMBER
genGausN:
    PUSH BP
    MOV  BP,SP
    PUSH SI                                             ! Save SI state

! GENERATE THE 3 UNIFORM SEQUENCES
    CALL genSeqs   
   
! GENERATE THE COMBINED SEQUENCE
    CALL genCmbA                           
   
! GENERATE GAUSSIAN
    PUSH (nUnif)                                        ! Number of uniforms to sum up for one gaussian
    CALL uni2gaus
    ADD SP, 2
test0:
    POP SI
    MOV  SP,BP
    POP BP
    RET
   
     
!   -----------------------------------------------------------------
!   GENERATE 3 LINEAR CONGRUENTIAL SEQUENCES
!   GIVEN LENGTH, POINTER, SEEDS

genSeqs:
    PUSH BP
    MOV  BP,SP
    PUSH DI                                             ! Save DI state
    PUSH SI
   
! GENERATE FIRST SEQUENCE (Jumping)
    PUSH 0                                              ! First combination of parameters
    CALL updPars                                    ! Assign parameters to a, c, m
    ADD SP,2                                            ! Clean up the stack from parameter index
    PUSH _nSeq                                  ! Length of sequence 1a on the stack
    PUSH rndSeq1                                ! Sequence 1a pointer to stack 4(BP) in called
    PUSH (seed1)                                    ! Seed 1 to stack
    CALL rndLp                                      ! Returns result in AX
    MOV (seed1),AX                              ! Update seed to last rand element
    ADD SP, 6                                       ! Clean up the stack from sequence data
   
! GENERATE SECOND SEQUENCE
    PUSH 2                                              ! Second combination of parameters
    CALL updPars                       
    ADD SP,2                               
    PUSH _nSeq                     
    PUSH rndSeq2                   
    PUSH (seed2)                       
    CALL rndLp
    MOV (seed2),AX                 
    ADD SP,6       

! GENERATE THIRD SEQUENCE
    PUSH 4                                 
    CALL updPars                       
    ADD SP,2                               
    PUSH _nSeq                     
    PUSH rndSeq3                   
    PUSH (seed3)                       
    CALL rndLp
    MOV (seed3),AX                 
    ADD SP,6
   
    POP SI                                              ! Retrieve DI state
    POP DI                                 
    MOV BP,SP
    POP BP
    RET
   

! -------------------------------------------------------------------
!   UPDATE PARAMETERS
! a, c, m get updated to a different combination
!   finds the parameter index on the stack
! ALTERS AX
updPars:
    PUSH BP
    MOV BP,SP
    PUSH SI
   
    MOV SI,4(BP)
    MOV AX, aVec(SI)
    MOV (a),AX
    MOV AX, cVec(SI)
    MOV (c),AX
    MOV AX, mVec(SI)
    MOV (m),AX
   
    POP SI
    MOV SP, BP
    POP BP
    RET


!   -----------------------------------------------------------------
!   GENERATE SEQUENCE FROM SEED
!   ALTERS AX, DX, CX
rndLp:         
    PUSH BP
    MOV  BP,SP
    PUSH DI
   
    MOV AX, 4(BP)                                       ! Get seed
    MOV DI, 6(BP)                                           ! Get sequence pointer
    MOV CX, 8(BP)                                       ! Initialize counter

! (a*[seed])+0 mod m
nxtRnd:
    MUL (a)                                
    ADD AX, (c)
    DIV (m)
    MOV AX, DX
    MOV (DI),DX                                         ! Store number in rndSeq
    ADD DI,2                                                    ! Increment pointer to stored rand vars
    LOOP nxtRnd
   
    POP DI
    MOV  SP,BP
    POP BP
    RET


!   -----------------------------------------------------------------
! COMBINE 3 SEQUENCES AND GENERATE
! NEW ONE WITH LONGER PERIOD   
! ALTERS CX, DX
genCmbA:       
    PUSH BP
    MOV  BP,SP
    PUSH DI                                                 ! Save register states
    PUSH SI
    PUSH BX
   
    MOV CX, (nUnif)                                     ! From _nSeq-1 to 0
    XOR DI, DI                                              ! Make sure the sequence pointers start from 0
    XOR SI,SI
   
cmbLp:                                                          ! Sum/subtract 3 sequences
    XOR DX,DX                                               ! Reset register
   
    MOV AX,rndSeq1(SI)
    MOV BX,rndSeq2(SI)
    ADD AX, BX
    ADC DX,0
   
    MOV BX,rndSeq3(SI)
    ADD AX,BX                          
    ADC DX,0
    DIV (m_gauss)  
                        ! If second number was to be subtracted (to be tested):
                        !cmbLp:                                    
                            !MOV DX,0
                            !MOV AX,rndSeq1(SI)
                            !MOV BX,rndSeq2(SI)
                            !SUB AX,BX                 
                            !JS negative                                    ! Handle negative case below
                            !! positive
                            !MOV BX,rndSeq3(SI)
                            !ADD AX,BX             
                            !DIV (m_gauss)                          ! Just divide the result.
                            !JMP store                                 
                            !negative:                                      ! Twos complement on 32 bits
                            !CWD
                            !NOT AX
                            !ADD AX,1
                            !NOT DX
                            !ADC DX,0
                            !DIV (m_gauss) 
    MOV rndSeq4(SI),DX                                          ! Store number in rndSeq4          
    ADD SI,2
    LOOP cmbLp
   
    !MOV SI,0
   
    POP BX
    POP SI
    POP DI                                                                  ! Retrieve DI state
    MOV  SP,BP
    POP BP
    RET


!   -----------------------------------------------------------------
!   TRANSFORM A BATCH OF UNIFORMS
!   TO A GAUSSIAN RANDOM VARIABLE
!
!   GENERAL FORMULA to get
!   mean req_avg, standard deviation req_std,
!   having n numbers from a Uniform [0-m]
!  
!   req_std*    [sum(...n..)-m/2]/(sqrt(n*m**2/12))  + req_avg
!
!   FORMULA with n=48, m approaching 16 bit.
!   Starting price of asset (range under 16 bit) startPr: 20,000
!   Standard deviation = 1% of Starting price = 200; req_std = 300; req_avg = 0
!   ---&gt; (200*sum(...48...)/2)/m_gauss -12*200 + 0
!   ---&gt;(100*sum(...48...))/m_gauss -2400
!  
!   Requires additions resulting up to 32 bits, multiplications 32*16 bits
!   EXPECTS the number of uniforms (48)on the stack
!   ALTERS AX, CX, DX

uni2gaus:
    PUSH BP
    MOV  BP,SP
    PUSH BX                                             ! Save register states
    PUSH SI
    PUSH DI
   
    MOV CX, 4(BP)                                   ! Get batch length
    XOR AX,AX                                           ! Initialize lower bits of Total
    XOR DX,DX                                           ! Initialize higher bits of Total
    XOR SI,SI                                               ! Start the 48 uniforms counter

! SUM UP THE 48 NUMBERS
sumLp:                                                      ! SUM UP THE 48 NUMBERS
    MOV BX,rndSeq4(SI)                          ! Fetch new number 
    ADD AX,BX                                           ! Add new number to lower bits of total
    ADC DX,0                                                ! If AX+BX generates carry, add it to DX
    ADD SI,2                                                ! Point to next number
    LOOP sumLp                                      ! Repeat until number of elements is 0

! MULTIPLY THE SUM BY HALF STD
    MOV CX, DX                                      ! Save Old Higher part of N
    MUL (halfStd)                                       ! Multiply the Lower part of N times halfStd
    MOV BX, DX                                          ! Save New Higher of Low
    XCHG AX, CX                                     ! Now CX contains the New Lower of Lower. AX contains Old Higher
    MUL (halfStd)                                       ! Multiply Old Higher times halfStd
    ADD AX, BX                                          ! Add New Higher of Low to New Low of Higher
                                                                    ! 32bit * 16 bit: no carry to Higher of Higher

    MOV DX, AX                                          ! High part result
    MOV AX, CX                                          ! Low part result
   
    DIV (m_gauss)                                       ! If m_gauss is big enough, the result will fit in AX
    SUB AX, (mean)                                  ! Subtract the mean
   
    MOV DI, (gaussCount)
    MOV gaussSeq(DI), AX                        ! Store
   
    POP DI
    POP SI
    POP BX                                                  ! Restore BX state
    MOV BP,SP
    POP BP
    RET


</pre>

Autant de séquences sont générées que d’itérations requises pour la méthode de Monte Carlo.

  • Chaque trajectoire génère un paiement (Payoff) qui dépend des paramètres financiers (niveaux de strike et de barrière).
  • En raison du nombre d’itérations dépassant les bits autorisés par le registre CX, un double cycle est nécessaire. Les sommes des paiements (Payoff) dépasseraient également les limites autorisées.
  • Dans la boucle interne, la moyenne des paiements est calculée ; dans la boucle externe, la moyenne des moyennes est calculée.
  • La moyenne du paiement est actualisée en fonction d’un taux R.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
<pre>!  THIS MODULE HANDLES THE CREATION OF A SET OF SIMULATED PRICE TRAJECTORIES
!   AND CALCULATES THE AVERAGE PAYOFF.
!

.SECT .TEXT            

!   -----------------------------------------------------------------
!   GENERATES A TRAJECTORY. PRINTS:
!       the 3 base uniform sequences;
!       the derived uniform sequence; the Gaussian sequence;
!       the brownian motion.

runEpr:
    PUSH BP
   
    CALL trjctry           
   
    ! PRINT
    CALL pr4Seq                         !   THE LAST RUN OF UNIFORM SEQUENCES
                                                        !   genfuncs.
    CALL prGaSeq                        !   GAUSSIANS
                                                        !   genfuncs.s
    CALL prGmb                          ! BROWNIAN MOTION
                                                        !   genfuncs.s
    POP BP
    RET

!   -----------------------------------------------------------------
! GENERATES MANY TRAJECTORIES
! COMPUTES AVERAGE AND PRESENT VALUE
! Yelds a mean value - the fair price
! A high number of trajectories (&gt; 16 bit) is achieved
! by running 2 loops
!
! EXPECTS the number of runs to be pushed on the stack:
!   2int &lt; 16 bit. The number of runs is their product.
! RETURNS the average Mc Price in AX

runMc:
   
    PUSH BP
    MOV BP, SP
    dbg3:
    MOV CX, 6(BP)                       ! Set higher counter
    PUSH 4(BP)                              ! Pass lower counter to function
   
    XOR AX,AX                               ! Resets the accumulator
    XOR DX, DX 

1:                                                  ! OUTER LOOP STARTS HERE
    PUSH CX                                 ! Save higher counter  
    PUSH AX                                 ! Save last cumulated values - lower word
    PUSH DX                                 ! Save last cumulated values - higher word
   
    CALL mcPart

    ! CUMULATE THE PRICES
    POP DX                                      ! Last cumulated values, higher word
    POP BX                                      ! Last cumulated values, lower word, go in BX
    ADD AX, BX                              ! Add the last generated price to the cumulated values
    ADC DX, 0                               ! Add carry if needed
   
    POP CX                                      ! Retrieve higher counter
    LOOP 1b                                 ! CONTINUE OUTER LOOP

    ! AVERAGE THE AVERAGES
    DIV 6(BP)                                   ! Divide by higher loop length to get the mean 
    MOV (mcPayOff), AX              ! Save the Montecarlo average value
    MOV SP, BP
    POP BP
    RET

!   -----------------------------------------------------------------
mcPart:
    PUSH BP
    MOV BP, SP
   

    MOV CX, 10(BP)                      ! Set CX to lower counter.
                                                        ! Finds the counter value on the stack before:
                                                        ! 3 saved values, the function address and the bp address
    XOR AX,AX                               ! Resets the accumulator
    XOR DX, DX
   
1: 
    dbg4:
    PUSH CX                                 ! Save loop counter before next functions
    PUSH AX                                 ! Save last cumulated values - lower word
    PUSH DX                                 ! Save last cumulated values - higher word
   
    CALL trjctry                                ! BUILD A TRAJECTORY
    CALL prFrstPlt                          ! Plot one of the first trajectories

    CALL payOff                             ! Must find last price in (lstBrPr). Returns payoff in AX
   
    ! CUMULATE THE PAYOFFS
    dbg5:                                          
    POP DX                                      ! Last cumulated values, higher word
    POP BX                                      ! Last cumulated values, lower word, go in BX
    ADD AX, BX                              ! Add the last generated price to the cumulated values
    ADC DX, 0                               ! Add carry if needed
   
    dbg6:
    POP CX
    LOOP 1b
   
    ! AVERAGE THE PAYOFFS
    DIV 10(BP)                              ! Divide by lower loop length to get the mean
    MOV SP, BP
    POP BP
    RET

!   -----------------------------------------------------------------
!   GENERATE A COMPLETE PRICE TRAJECTORY
!   Stored in brownSeq
!   RETURNS: AX, the last day price
trjctry:                                           
! GENERATE A GAUSSIAN SEQUENCE

    PUSH (days)                         ! Push length of sequence
    CALL genGaSeq                       ! series2.s
    ADD SP, 2                               ! Clean up stack   
   
! GENERATE BROWNIAN MOTION
    PUSH (startPr)
    CALL gbm                                ! series.s
    ADD SP, 2                               ! Clean up stack
!   APPLY BARRIERS
    CALL applBarr
    RET
   
!   -----------------------------------------------------------------
!   GENERATE A PAYOFF
!  
!   EXPECTS: (lstBrPr) in memory, the last price of the sequence
!   RETURNS: AX, the payoff
!   ALTERS AX, DX
payOff:
    PUSH BP
    MOV BP, SP
   
    MOV AX, (lstBrPr)
    MOV DX, (strike)
    CMP (put),TRUE
    JNE 1f
    XCHG AX, DX
1:SUB AX, DX
    JNS 2f 
    XOR AX, AX
2:
    MOV SP, BP
    POP BP
    RET
   


   
!   -----------------------------------------------------------------
!   DISCOUNT A PRICE   
!   Uses the full period, base rate of return, rateR.
!  
!   RETURNS: AX, the discounted price
!   EXPECTS: AX, the future payoff. (days)
!   ALTERS AX, DX
dscnt:
                                                            ! The price is in AX
    XOR DX,DX
    MOV BX, AX                                  ! Save price for later
    MUL (rateR)                                 ! Multiply price by return - could use AX-DX
    DIV (basePct)                               ! Percentify the price movement - AX is enough
    SUB BX, AX                                  ! Subtract the discount from the price
                                                            ! Always &gt;= 0
    MOV AX, BX                                  ! Price back to AX
    RET

.SECT .DATA
.SECT .BSS             
</pre>

Les valeurs de chaque trajectoire seront affichées sur l’interface textuelle à l’aide de caractères ASCII.

  • Une zone de traçage (plot area) est caractérisée par un certain nombre (paramétrable) de lignes et de colonnes. Si la trajectoire dépasse le nombre de colonnes prévu, une nouvelle zone de traçage est générée.
  • Toutes les valeurs de la trajectoire sont mises à l’échelle pour tenir à l’intérieur de cette matrice – la zone de traçage. La gamme des prix est segmentée en fonction du nombre de colonnes disponibles, de manière à ce que l’ensemble de la trajectoire soit toujours visible (et n’entraîne pas de débordement dans la matrice, constituée d’un espace mémoire de longueur n_colonnes * n_lignes).
  • Pendant la simulation de Monte Carlo, certaines trajectoires sont dessinées. Afin qu’elles restent visibles pendant un certain temps, un grand nombre d’instructions NOP (no operation) est inséré entre elles.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
<pre>!  PRINTS ASSET PRICE TRAJECTORIES

.SECT .TEXT

!   -----------------------------------------------------------------
! DRAWS A FULL PLOT AREA
! Draws a partial plot area [_nCols] long.
!   Continues drawing until the accumulated prtFrm
!   is bigger than [_days], then draws the last part
!   with the difference
!   SI accumulates the pointer position, in terms of days
!  
!  
fullPlot:
    PUSH BP
    MOV BP,SP
    PUSH SI
    PUSH DI
    PUSH BX
    MOV SI, 0
    MOV DI, 0
    MOV BX, (days)                                  ! For comparison
   
! GET THE OPTIMAL PARAMETERS FOR PLOTTING
    PUSH brownSeq                                   ! Push the brownian sequence
    PUSH (days)                                     ! Push the length of the sequence
    PUSH _nRows                                 ! Push the number of rows of the plot
    CALL plotPars                                       ! Get the optimal parameters for plotting
                                                                    ! Shrink in AX, Shift in DX, max in CX
    ADD SP, 6
   
    MOV (lstMinPr), DX                              ! Copy min and maxin global variable
    MOV (lstMaxPr), CX                          ! Used for the plot frame in prPlot
   
! GET THE PLOTTABLE VALUES
    ! The next functions require on the stack:
    ! min price, shrink, days, price sequence, axis sequence
    PUSH DX
    PUSH AX
    PUSH (days)
    PUSH brownSeq
    PUSH redPrSeq
    CALL redPric                                        ! Reduce prices to axis values
    ADD SP, 6                                           ! Make place for the STRIKE parmeters
    PUSH 1                                                  ! Strike is only 1 number
    PUSH strike
    PUSH redStrk                       
    CALL redPric                                        ! Reduce strike price to axis values
    ADD SP,10
   
1:
    MOV SI, DI                                          ! Prepare next frame
    ADD DI, _nCols
    CMP DI, BX
    JGE 2f                                                  ! If DI &gt; days, draw the remaining part and exit
    PUSH redPrSeq
    PUSH _nCols                                     ! Otherwise draw a full col-length frame
    PUSH SI                                             ! Starting day
    CALL partPlot                                       ! Draw a plot frame
    ADD SP, 6

    JMP 1b 
   
    2:                                                          ! draw the remaining part and exit
    SUB BX, SI 
    PUSH redPrSeq      
    PUSH BX                
    PUSH SI                                             ! Starting day
    CALL partPlot                                       ! Draw a plot frame
    ADD SP, 6
   
    POP BX
    POP DI
    POP SI
    MOV SP,BP
    POP BP     
    RET

!   -----------------------------------------------------------------
!   TRANSFORMS THE PRICES TO PLOTTABLE VALUES
!   Subtracts the minimum value, then divides by the shrink factor
!   EXPECTS: red. price seq. address, displacement, shrink,
!       price sequence length,price sequence address on the stack
!   ALTERS CX

redPric:
    PUSH BP
    MOV BP,SP
    PUSH SI
    PUSH DI
    PUSH BX
   
   
    MOV SI, 6(BP)
    MOV DI, 4(BP)
    MOV BX,0

    CMP 10(BP),0                                        ! If all the prices are equal, modify shrink and displacement.
    JNE 1f                                                  ! Otherwise, continue
    MOV AX, 12(BP)
    MOV 10(BP), AX
    MOV 12(BP), 0
   
   
1:  MOV CX, 8(BP)                               ! Set loop to number of days
   
2:XOR DX,DX
    MOV AX, (BX)(SI)                                ! Get number from prices sequence
    SUB AX, 12(BP)                                  ! Shift it by displacement
    DIV 10(BP)                                          ! Divide by shrink
   
    MOV (BX)(DI), AX
    ADD BX,2
    LOOP 2b
   
    POP BX
    POP DI
    POP SI
    MOV SP,BP
    POP BP     
    RET


!   -----------------------------------------------------------------
! COMPUTES OPTIMAL PARAMETERS FOR PLOTTING
!   The SHRINK factor is the resolution of the plot. It divides the
!       price value.
!   The SHIFT parameter is the lowest value. It is subtracted from the
!       price to center the plot.
! RETURNS:
!       SHRINK factor in AX,
!       SHIFT factor in DX (also the min price), max price in CX
! EXPECTS:
!       brownian sequence pointer, sequence length,  
!       number of rows on the stack
! ALTERS: AX, DX, CX
!
plotPars:
    PUSH BP
    MOV BP,SP
    PUSH SI

    MOV SI, 8(BP)                                       ! Put brownian sequence pointer in SI
    MOV CX, 6(BP)                                   ! Length of the br. sequence
   
    MOV DX, 32767                                   ! Keeps the minimum value found in the sequence
    MOV AX, 0                                           ! Keeps the maximum value found in the sequence
   
1:CMP DX, (SI)
    JLE 2f                                                  ! If min value is smaller than current value, continue on 2
    MOV DX, (SI)                                        ! Otherwise, set min value
2:CMP AX, (SI)
    JGE 3f                                                  ! If max value is greater than current value, continue on 3
    MOV AX, (SI)                                        ! Otherwise, set max value
3:
    ADD SI,2
    LOOP 1b

    PUSH AX                                             ! Save max and min values
    PUSH DX
    SUB AX, DX                                          ! Get range
! SHRINK FACTOR in AX
    XOR DX, DX                                          ! Clean DX for division
    DEC 4(BP)
    DIV 4(BP)                                               ! Divide by rows number to get the SHRINK factor

! SHIFT PARAMETER IS DX, being DX the minimum value
    POP DX
! MAX VALUE in CX
    POP CX
   
    POP SI
    MOV SP,BP
    POP BP     
    RET


!   -----------------------------------------------------------------
! DRAWS A PARTIAL PLOT AREA
!
! EXPECTS source sequence pointer, sequence length, sequence on the stack
partPlot:
    PUSH BP
    MOV BP,SP
    PUSH BX

    PUSH 6(BP)                                          ! Length of the sequence to draw (excluding newlines)
    CALL voidPlt                                        ! Build an empty plot area
                                                                    ! Optimization: could be computed just once, in fullPlot
    ! 6(BP) still on the stack, used by the next function
    CALL cpVoid                                     ! Copy the void plot area to the trajectory plot area
   
    ! 6(BP) still on the stack, used by the next function
    MOV BX, 4(BP)                                   ! Get the offset of the days for the next plot (number of days already plotted)
    SHL BX,1                                                ! Double the offset - the days need be converted to WORD
    ADD BX, 8(BP)                                   ! Add the starting sequence pointer (redPrSeq)
    PUSH BX                                             ! Push the new pointer for the prices on the stack
    PUSH  (redStrk)                                 ! Push the strike
    CALL addDots                                        ! Add dots to the plot area
    ADD SP,6                                                ! Clean up: BX and 6(BP)
    CALL prPlot                                         ! Print the plotted area

    POP BX
    MOV SP,BP
    POP BP     
    RET
   
   
!   -----------------------------------------------------------------
! BUILDS AN EMPTY PLOT AREA
!
! EXPECTS number of cols on the stack
! ALTERS AX, DX
voidPlt:   
    PUSH BP
    MOV BP,SP
    PUSH DI
    PUSH BX
   
    MOV DI, voidMat
    MOV DX, _nRows
    MOV BX, 4(BP)                                   ! Number of columns to draw
1:MOV CX, BX                                            ! Number of columns to draw
    ! FILL A ROW WITH NULLS
    MOVB AL," "                                         ! Fill value
    REPNZ STOSB                                 ! space fill until CX==0
    MOVB AL,"\n"                                        ! Place a newline at the end
    STOSB                                                   ! =
    DEC DX                                              ! Move to next row
    LOOPNZ 1b
    MOVB AL, 0
    STOSB                                                   ! Signal string ending
   
    POP BX
    POP DI
    MOV SP,BP
    POP BP     
    RET
   
!   -----------------------------------------------------------------
! COPY AN EMPTY PLOT AREA IN trjPlot
!
! EXPECTS number of cols on the stack
cpVoid:
    PUSH BP
    MOV BP,SP
    PUSH SI
    PUSH DI
    PUSH BX

    MOV SI, voidMat
    MOV DI, trjPlot
    ! Copy the rows*cols + nrows (the newlines)+1 end string
    MOV AX, _nRows
    MOV BX, 4(BP)                                   ! Number of cols
    INC BX                                                  ! Make space for newline
    MUL BX
    INC AX                                                  ! Line ending will also be copied
    MOV CX, AX
    REPNZ MOVSB
   
    !MOV AX,0
    !MOVSB
   
    POP BX
    POP DI
    POP SI
    MOV SP,BP
    POP BP     
    RET
   
!   -----------------------------------------------------------------
! ADDS THE DOTS TO THE PLOT AREA
! ADDS STRIKE PRICE, BARRIERS
!
! EXPECTS sequence length, sequence pointer, reduced strike on the stack
! ALTERS AX, DX
addDots:
    PUSH BP
    MOV BP,SP
    PUSH BX
    PUSH DI
    PUSH SI
   
    XOR SI, SI
    XOR DI, DI
    MOV CX, 8(BP)                                   ! Get sequence length
    PUSH CX                                             ! Get days + 1 and push it on the stack --&gt; LOCAL VARIABLE -8(BP)
    INC -8(BP)                                          ! =

1:
! DOTS:
! The memory location of a dot is:
!   Location of row (from the axis-price sequence) +  col (the current in the cycle)
!   Price is _nRows-price, to let the plot start on the lower border
!   price*(row_length+1) + col, where +1 refers to the newline
! STRIKE AND BARRIERS:
!   Same as above, but the price comes from the appropriate global variable

! DRAW STRIKE
    MOV BX, 4(BP)                                   ! Get the row of the strike price
    MOV AX, _nRows
    SUB AX,BX                                           ! Reduced price (in sequence pointer+SI) to AX, in reverse order   
    MUL -8(BP)                                          ! -8(BP) is the local variable for [days+1]
                                                                    ! Now AX contains memory location of row                                                       
    MOV BX,AX                                           ! Location of row goes to BX for Register index displacement   
    MOVB trjPlot(BX)(DI), "="                   ! Place a hyphen in  trjPlot where row = strike, column DI

! DRAW DOT
! COLUMN IS IN DI
! GET ROW IN AX

    MOV BX, 6(BP)                                   ! Move sequence pointer from stack to BX   
    MOV AX, _nRows-1                            ! dont want max rows
    SUB AX,(BX)(SI)                                 ! Reduced price (in sequence pointer+SI) to AX, in reverse order   
   
! GET MEMORY LOCATION OF ROW according to formula above
    MUL -8(BP)                                          ! -8(BP) is the local variable for [days+1]
                                                                    ! Now AX contains memory location of row                                                       
    MOV BX,AX                                           ! Location of row goes to BX for Register index displacement   
    MOVB trjPlot(BX)(DI), "|"                   ! Place a dot in  trjPlot where row = price, column DI
    INC DI                                                  ! Next column
    ADD SI,2                                                ! Next pointer for price sequence
    LOOP 1b                                             ! Plot one more column 
   
    ADD SP,2
    POP SI
    POP DI
    POP BX
    MOV SP,BP
    POP BP     
    RET


!   -----------------------------------------------------------------
! PRINTS THE PLOT AREA
!   Prints the plotstring and 2 strings as divisors with high and low prices
!   For the frame, finds the minimum, maximum, last prices of the
!       brownian sequence in lstMinPr, lstMaxPr, lstBrPr
!
! ALTERS AX, DX
prPlot:
    PUSH BP
    MOV BP,SP
    PUSH DI

! TOP SEPARATOR
    MOV DI, voidStr
    MOVB AL, "\n"
    STOSB
    MOVB AL, "#"                                        ! Print a separator nCols times
    MOV CX, (nCols)
    REPNZ STOSB
    MOVB AL, "\n"
    STOSB
    MOVB AL, 0                                          ! End the string
    STOSB                      
   
    PUSH voidStr
    PUSH _PRINTF
    SYS
    ADD SP, 4  

! TOP LEFT
    MOV AX,(lstMaxPr)
    CALL axdxDecN
    PUSH DX
    PUSH AX
    PUSH maxStr1
    PUSH _PRINTF
    SYS
    ADD SP, 8
   
! TOP CENTER
    MOVB AL, "-"
    MOV DI, voidStr
    MOV CX, (nCols)                        
    SUB CX, (maxStrSp)                          ! If there is space enough to add hyphens, add as many as the columns,
    JNS 1f                                                  ! subtracting the start and end strings. Otherwise, repeat 0 times
    XOR CX, CX
1:REPNZ STOSB
    MOVB AL, 0                                          ! End the string
    STOSB                      

    PUSH voidStr
    PUSH _PRINTF
    SYS
    ADD SP, 4
   
! TOP RIGHT
    MOV AX,(lstBrPr)
    CALL axdxDecN
    PUSH DX
    PUSH AX
    PUSH maxStr2
    PUSH _PRINTF
    SYS
    ADD SP, 8
   
! PLOT THE TRAJECTORY
    PUSH trjPlot
    PUSH _PRINTF
    SYS
    ADD SP, 4
   
! BOTTOM LEFT
    MOV AX,(lstMinPr)
    CALL axdxDecN
    PUSH DX
    PUSH AX
    PUSH minStr1
    PUSH _PRINTF
    SYS
    ADD SP, 8

! BOTTOM CENTER
    MOVB AL, '-'
    MOV DI, voidStr
    MOV CX, (nCols)
    SUB CX, (minStrSp)                                  ! If there is space enough to add hyphens, add as many as the columns,
    JNS 1f                                                          ! subtracting the start and end strings. Otherwise, repeat 0 times
    XOR CX, CX
1:REPNZ STOSB
    MOVB AL, "+"
    STOSB
    MOVB AL, "\n"
    STOSB
    MOVB AL, 0                                                  ! End the string
    STOSB                      
   
    PUSH voidStr
    PUSH _PRINTF
    SYS
    ADD SP, 4
   
    POP DI
    MOV SP,BP
    POP BP         
    RET
   

.SECT .DATA

.SECT .BSS 
redPrSeq: .SPACE _days*2
voidMat: .SPACE _nRows*_nCols+_nRows+1
.ALIGN 2
trjPlot: .SPACE  _nRows*_nCols+_nRows+1
.ALIGN 2
topBfr: .SPACE 1000
botBfr: .SPACE 1000

</pre>

L’interaction avec l’utilisateur comprend, en plus de la génération des composantes aléatoires, le choix de la direction : acheter une PUT ou une CALL. Après avoir évalué le prix de l’option, une dernière trajectoire sera générée ; à partir de celle-ci, on obtiendra le Payoff. Le coût du dérivé sera soustrait, et le résultat sera communiqué.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
<pre>.SECT .TEXT

!   -----------------------------------------------------------------
!   PRINT THE FIRST N PLOTS WITH DELAY
!   For every run in Montecarlo, checks
!   if it must be printer. Inserts NOPs in order
!   to let the user see the plot.
!   Keeps count in a global variable.
!   Used in mtCarlo.s -&gt; mcPart

prFrstPlt: 
    CMP (pltCntr), MAXMCPLT                             ! check counter. If it reaches constant, jmp to return
    JGE 3f
    CALL fullPlot

    MOV CX, NOP1    ! First part of waiting cycle
1:PUSH CX
    MOV CX, NOP2   
2:XCHG AX, AX       ! Insert NOP
    LOOP 2b
    POP CX
    LOOP 1b
    ! Increase counter
    INC (pltCntr)
3:
    RET


!   -----------------------------------------------------------------
!   PRINT GEOMETRIC BROWNIAN MOTION
prGmb:
    PUSH (days)                                         ! Length of sequence to the stack
    PUSH brownSeq                                       ! Sequence 1a pointer to stack 4(BP) in called
    CALL prDecSeq
    ADD SP,4
    MOV AX,prDiv                                            ! Msg to user
    CALL prnt_msg
    RET
   
!   -----------------------------------------------------------------
! PRINT GAUSSIAN SEQUENCE
prGaSeq:   
    PUSH (days)                                         ! Length of sequence to the stack
    PUSH gaussSeq                                       ! Sequence 1a pointer to stack 4(BP) in called
    CALL prSeq
    ADD SP,4
    MOV AX,prDiv                                            ! Msg to user
    CALL prnt_msg
    RET

!   -----------------------------------------------------------------
! PRINT THE 4 SEQUENCES
! Alters AX
pr4Seq:
! PRINT FIRST SEQUENCE 
   
    PUSH (nUnif)                                            ! Length of sequence 1b on the stack
    PUSH rndSeq1                                        ! Sequence 1a pointer to stack 4(BP) in called
    CALL prSeq
    ADD SP,2
    MOV AX,prDiv                                            ! Msg to user
    CALL prnt_msg
   
! PRINT SECOND SEQUENCE
    PUSH rndSeq2                                        ! Sequence 1a pointer to stack 4(BP) in called
    CALL prSeq
    ADD SP,2
    MOV AX,prDiv                                            ! Msg to user
    CALL prnt_msg
   
! PRINT THIRD SEQUENCE
    PUSH rndSeq3                                        ! Sequence 1a pointer to stack 4(BP) in called
    CALL prSeq
    ADD SP,2
    MOV AX,prDiv                                            ! Msg to user
    CALL prnt_msg

! PRINT COMBINED SEQUENCE
    PUSH rndSeq4                                        ! Sequence 1a pointer to stack 4(BP) in called
    CALL prSeq
    ADD SP,4
    MOV AX,prDiv                                            ! Msg to user
    CALL prnt_msg
   
    RET

!   -----------------------------------------------------------------
! PRINT SEQUENCE
! EXPECTS number of chars , then sequence pointer on the stack
prSeq: 
    PUSH BP
    MOV BP,SP
    PUSH SI
   
    MOV CX,6(BP)                                        ! Get  total days
    MOV SI, 4(BP)                                       ! Get position of prices
1: 
    MOV AX, (SI)                                        ! Get a price
    ADD SI, 2
    PUSH AX
    PUSH prNum
    PUSH _PRINTF
    SYS
    ADD SP, 6
    LOOP 1b
   
    tst1:
    POP SI
    MOV SP,BP
    POP BP         
    RET

!   -----------------------------------------------------------------
! PRINT DECIMAL SEQUENCE
!   Same as above, but prints a decimal number
! EXPECTS number of chars , then sequence pointer on the stack
! ALTERS AX, CX, DX
prDecSeq:  
    PUSH BP
    MOV BP,SP
    PUSH SI
   
    MOV CX,6(BP)                                        ! Get  total days
    MOV SI, 4(BP)                                       ! Get position of prices
   
1: 
    MOV AX, (SI)                                        ! Get a price  
    CALL axdxDecN                                   ! Produce a decimal string using AX.
                                                                    ! result in dcmlBuf
    PUSH DX
    PUSH AX
    PUSH frmtDecN
    PUSH _PRINTF
    SYS
   
    ADD SP, 4
    ADD SI, 2                                               ! Prepare for next price   
    LOOP 1b
   
    POP SI
    MOV SP,BP
    POP BP         
    RET

!   -----------------------------------------------------------------
! DECIMAL NUMBER
!   Transforms an int number into a decimal number
! EXPECTS number in AX
! RETURNS values in AX, DX
axdxDecN:
    PUSH BP
    MOV BP,SP
   
    XOR DX,DX
    DIV (HUNDRED)
   
    MOV SP,BP
    POP BP
    RET

!   -----------------------------------------------------------------
! PRINTS INFORMATION ON PARAMETERS
! All the parameters are pushed on the stack
! and printed
! The values are divided by 100
! ALTERS AX, DX
prInfo1:
    PUSH BP
    MOV BP,SP
   
    PUSH msg2
    PUSH _PRINTF
    SYS
    PUSH msg3
    PUSH _PRINTF
    SYS
    MOV AX, (floor)
    DIV (HUNDRED)
    PUSH AX
    MOV AX, (cap)
    DIV (HUNDRED)
    PUSH AX
    MOV AX, (strike)
    DIV (HUNDRED)
    PUSH AX
    PUSH (reqStd)
    PUSH (drift)
    PUSH (rateR)
    PUSH msg4
    PUSH _PRINTF
    SYS
    PUSH msg5
    PUSH _PRINTF
    SYS
   
    MOV SP,BP
    POP BP
    RET

!   -----------------------------------------------------------------
! ASK PUT
! Asks the user if he wants a put (p)
! ALTERS AX
askPut:
    PUSH BP
    MOV BP,SP
   
    ! PRINT REQUEST
    PUSH msg6
    PUSH _PRINTF
    SYS

    ! GET ANSWER
    PUSH _GETCHAR
    SYS                            
    CMPB AL,'p'            
    JNE 1f                             
    MOV (put), TRUE                                     ! It is a PUT
    MOV AX, msg6p
    JMP 2f
1:MOV (put), FALSE                                      ! It is a CALL
    MOV AX, msg6c
2:PUSH AX
    PUSH _PRINTF
    SYS
   
    MOV SP,BP
    POP BP
    RET

!   -----------------------------------------------------------------
! TELL THE COST
!   Tells the user the discounted, average Montecarlo price
!   of the option
prInfo2:
    PUSH BP
    MOV BP,SP
   
    MOV AX, (dscPayOff)
    CALL axdxDecN
    PUSH DX
    PUSH AX
    MOV AX,  (mcPayOff)
    CALL axdxDecN
    PUSH DX
    PUSH AX
    PUSH msg7
    PUSH _PRINTF
    SYS
   
   
    MOV SP,BP
    POP BP
    RET

!   -----------------------------------------------------------------
! EXPLAIN THE UNIFORMS
prInfo3:
    PUSH BP
    MOV BP,SP
    PUSH msg8
    PUSH _PRINTF
    SYS
    MOV SP,BP
    POP BP
    RET

!   -----------------------------------------------------------------
! EXPLAIN THE GAUSSIANS
prInfo4:
    PUSH BP
    MOV BP,SP
    PUSH msg9
    PUSH _PRINTF
    SYS
    MOV SP,BP
    POP BP
    RET

!   -----------------------------------------------------------------
! EXPLAIN THE UNIFORMS
prInfo5:
    PUSH BP
    MOV BP,SP
    PUSH msg10
    PUSH _PRINTF
    SYS
    MOV SP,BP
    POP BP
    RET

!   -----------------------------------------------------------------
! SHOW THE TRAJECTORY
prInfo6:
    PUSH BP
    MOV BP,SP
    PUSH msg11
    PUSH _PRINTF
    SYS
    MOV SP,BP
    POP BP
    RET

!   -----------------------------------------------------------------
!   TELL THE OUTCOME
!   Subtracts the previously computed discounted
!   Montecarlo payoff from the new payoff
!
!   EXPECTS payOff in AX
tellOutc:
    PUSH BP
    MOV BP,SP
    SUB AX, (dscPayOff)
    JS 1f
    PUSH AX
    CALL axdxDecN
    PUSH DX
    PUSH AX
    PUSH msg12a
    JMP 2f
1:NEG AX
    PUSH AX
    CALL axdxDecN
    PUSH DX
    PUSH AX
    PUSH msg12b
   
2:PUSH _PRINTF
    SYS
    MOV SP,BP
    POP BP
    RET
   
!   -----------------------------------------------------------------
! PRINT A TEXT AND POSSIBLY A NUMBER
! Requires string pointer in AX, number in DX
prnt_msg:
    PUSH BP
    MOV BP,SP
    PUSH DX
    PUSH AX
    PUSH _PRINTF
    SYS
    MOV SP,BP
    POP BP
    RET

!   -----------------------------------------------------------------
! WAITS FOR KEYPRESS
pause:                             
    PUSH BP
    MOV BP,SP
    PUSH _GETCHAR
    SYS
    MOV SP,BP
    POP BP
    RET

!   -----------------------------------------------------------------
!   INSERTS NEW LINES TO CLEAR THE SCREEN
cls:                                        !
    PUSH BP
    MOV BP,SP
    PUSH clear
    PUSH _PRINTF
    SYS
    MOV SP,BP
    POP BP
    RET
   
</pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<pre>! This file contains parameters that are allowed to be changed
!   for debugging or usage.

!   ######################################
!   USER MODIFIABLE DATA

!   -----------------------------------------------------------------
!   FINANCIAL DATA

 _days = 252!45                                     ! Length of the generated final sequence. Note: Tracer only supports up to 45.
_startPr = 10000                                        ! The value of the asset at T0.
                                                                    !   Should be small enough to fit in a register when growing,
                                                                    !       big enough to get meaningful results when manipulating.
                                                                    !       Multiple of 10.000 gets the drift right
                                                                    !   Also used as the quotient of percent values
_bpDrift =  0!25                                        ! Basis points; eg: 0.25% of 20000 basePct yelds 50 absolute
 _bpReqStd=100                                      ! Basis points; eg: 0.100% of 20000 basePct yelds 200 absolute.
                                                                    ! The absolute value should be a multiple of 4 for a good mean calculation
_rateR = 200                                            ! Rate of return - yearly, in basis points.
                                                                    ! Eg: price in T252 = 30000; bpR = 200; basePct = 20000 -&gt; return 1%
                                                                    ! Discount in T0: (30000*200)/20000=300
 _put = TRUE
 _strike = 10000
 _cap = 12000
 _floor = 8000
 

!   ######################################
!   DEBUG AND PROGRAM
 
!   -----------------------------------------------------------------
! PLOTS
! Number of rows and columns
_nRows = 30
_nCols = 150

!   -----------------------------------------------------------------
 _debug = FALSE                                     ! TRUE if debug mode, FALSE otherwise
                                                                        ! If DEBUG, jumps over the user input with preset values
 _dbgSd1 = 50
 _dbgSd2 = 70
 _dbgSd3 = 90

 
.SECT .TEXT
.SECT .DATA

.SECT .BSS

! SEQUENCES
rndSeq1: .SPACE 2*_nSeq
rndSeq2: .SPACE 2*_nSeq
rndSeq3: .SPACE 2*_nSeq
rndSeq4: .SPACE 2*_nSeq

! GAUSSIAN VARIABLES
gaussSeq: .SPACE _days*2

! BROWNIAN MOTION
brownSeq: .SPACE _days*2
</pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
<pre>.SECT .TEXT
!   -----------------------------------------------------------------
!   INITIALIZE VARIABLES
!   Alters AX, CX, DX

initVars:                                      
    ! PERFORMS SOME NEEDED CALCULATIONS ON THE PARAMETERS  

    ! Required Standard Deviation, as a base value
    XOR DX, DX
    MOV AX, (basePct)
    DIV (pcFier)
    MUL (bpReqStd)
    MOV (reqStd), AX   
   
    ! Normalizer-mean calculated (in accordance with the 48 summation formula) 
    XOR DX, DX
    MOV AX, (reqStd)
    SHR AX,1                                                ! Divide by 4
    SHR AX,1
    MUL (nUnif)                                         ! Multiply by 48
    MOV (mean), AX
       
    ! Drift, as a base value
    XOR DX, DX
    MOV AX, (basePct)
    DIV (pcFier)
    MUL (bpDrift)
    MOV (drift), AX

    !Half of required standard deviation, base value
    !   (in accordance with the 48 summation)
    MOV AX, (reqStd)
    SHR AX,1   
    MOV (halfStd), AX
   
    ! rateR, as a base value
    XOR DX, DX
    MOV AX, (basePct)
    DIV (pcFier)
    MUL (bpRateR)
    MOV (rateR), AX
   
    RET
   
!   -----------------------------------------------------------------
    .SECT .DATA

!   -----------------------------------------------------------------
! MISCELLANEOUS
    debug: .WORD _debug                         ! 1 if debug mode, 0 otherwise
    HUNDRED: .WORD _HUNDRED     ! 100

!   -----------------------------------------------------------------
!   MONTECARLO
hMcCount: .WORD _hMcCount               ! 100
lMcCount: .WORD _lMcCount                   ! 100        100 * 100 = 10k runs
pltCntr: .WORD ZEROINT  ! 0 Counter of Montecarlo plots displayed

!   -----------------------------------------------------------------
! FINANCIAL DATA
!   By using the percentifier, the basis point values are made independent respect the
!   base price of the asset.

    days: .WORD _days                               ! 252 Number of time steps
    startPr: .WORD _startPr                         ! 20000 Starting price of the asset
   
    ! DevStd and Average are expressed as a percentage multiplied by
    ! the base number
    basePct: .WORD _startPr                     ! 20000 Used to get percent values

    pcFier: .WORD _pcFier                           ! 10000      Used to transform drift, std, r
    bpDrift: .WORD _bpDrift                     ! 25                 Relative - basis points
    bpReqStd: .WORD _bpReqStd           ! 100 daily stdev of the asset - basis points
    bpRateR: .WORD _rateR                       ! 200 Rate of return - year, in basis points.
   
    strike: .WORD _strike                               !   20000 Strike price of the asset for the option
    redStrk: .WORD ZEROINT 
    cap: .WORD _cap
    floor: .WORD _floor
   
    put: .WORD _put ! TRUE  Boolean. The option behaves like a put if True, as a call if False
   
    mcPayOff: .WORD 0
    dscPayOff: .WORD 0

!   -----------------------------------------------------------------
! GAUSSIANS
    m_gauss:    .WORD   32362                   ! For the combined sequence, LCG
    nUnif: .WORD _nSeq  ! 48                        ! Number of uniforms to sum up

!   -----------------------------------------------------------------
! BROWNIAN MOTION
    lstBrPr:  .WORD 0                                   !Last brownian price computed
    lstMinPr:  .WORD 0                                  !Minimum brownian price computed
    lstMaxPr:  .WORD 0                              !Maximum brownian price computed
   

!   -----------------------------------------------------------------
! UNIFORMS
! a, c, m  coefficients of LCG are stored into vectors: for each index into them,
! a different combination of parameters is chosen

    a:  .SPACE  2              
    c:  .SPACE  2      
    m:  .SPACE  2
    aVec:   .WORD 157, 146, 142
    cVec:   .WORD 0, 0, 0
    mVec: .WORD 32363, 31727, 31657

!   ######################################
!   MESSAGES AND RELATED PARAMETERS
 
!   -----------------------------------------------------------------
! PLOT
!   ----&gt; prTraj.s
    maxStrSp:   .WORD 46                            ! Space taken by the maxStr and minStr
    minStrSp: .WORD 20                              ! on the plot borders
    nRows:  .WORD _nRows                        ! 30     Rows and columns of the plot area
    nCols:  .WORD _nCols                            ! 100
    voidStr:    .SPACE 1000                         ! For the frame
    maxStr1: .ASCIZ "\n+ %d.%02d  $ MAX VALUE"
    maxStr2: .ASCIZ " %d.%02d  $ AT EXPIRATION + \n"
    minStr1: .ASCIZ "\n+ %d.%02d  $ MIN VALUE"

.ALIGN 2

!   -----------------------------------------------------------------
! INPUT
!   ----&gt;genrand.s
    lp_chaos: .WORD 3
    n_chars: .WORD 2                                ! At least n_chars pressed before exiting the read loop
    bck_chars: .WORD 2                          ! If user exits too early, decrease counter by bck_chars

!   -----------------------------------------------------------------
! OUTPUT
!   ----&gt;genrand.s, prFuncs.s
    k_push: .ASCIZ "KEEP PUSHING!!!!!!"
    prompt_ms: .ASCIZ "a.Press ENTER for a few seconds (count to 10)\nb.Press any other key\nc.Press ENTER again, once"
    prNum: .ASCIZ "%d "
    clear: .ASCIZ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
    frmtDecN: .ASCIZ "%d.%02d "
   
!   ----&gt;main.s
    prDiv: .ASCIZ "\n-------------------------------------------------------------------\n"
    step: .ASCIZ "\n=====================\nSTILL %d TO GO\n"
   
!   -----------------------------------------------------------------  
! MESSAGES
    msg1: .ASCIZ "2) NOW: CREATE CHAOS!!\nCharge your generator by pressing [ENTER... - ANY KEY - ENTER] 3 times\n"
    msg2: .ASCIZ "*******************************************\n*                                         *  \n* WELCOME TO THE BARRIER OPTION SIMULATOR * \n*                                         *  \n*******************************************\n"
    msg3: .ASCIZ "\n\n1) Choose the option type\n2) Generate randomness\n3) Wait for Montecarlo pricing\n4) See if you gain or loose\n\n\nBuy a CALL or a PUT "
    msg4: .ASCIZ "on an asset where:\nR (Basis Points): %d\nDRIFT (Basis Points): %d\nSTANDARD DEVIATION (Basis Points): %d\nSTRIKE PRICE: %d\nCAP: %d\nFLOOR: %d\n\n"
    msg5: .ASCIZ "These parameters are modifiable in the source code. Rows and columns of the plot can also be set. \nPress ENTER to continue..."
    msg6: .ASCIZ "\n\n1) Please, CHOOSE YOUR OPTION. Enter [p] (lowercase) for a PUT, any other character for a CALL. Then press ENTER.\nType:  "
    msg6p: .ASCIZ "You own a PUT option! \nPress ENTER..."
    msg6c: .ASCIZ "You own a CALL option! \n3) Now, run Montecarlo\n\nPress ENTER..."
    msg7: .ASCIZ "\n\n\nThe estimated payoff of your derivative is %d.%02d$ in a year\nNow it costs you %d.%02d$\n\n4) Now, see what happens to the underlying asset in the next year:\n\nPress ENTER..."
    msg8: .ASCIZ "\n\n\n(See how a trajectory is made)\nThe next 4 sequences are uniform distributions. They will be used to generate a single gaussian random variable\n\nPress ENTER...\n"
    msg9: .ASCIZ  "\n\n\n(See how a trajectory is made)\nThat way, a sequence of gaussians is built\n\nPress ENTER...\n"
    msg10: .ASCIZ  "\n\n\nTHESE ARE YOUR ASSET PRICES:\n\nPress ENTER...\n"
    msg11: .ASCIZ  "\n\n\nTHIS IS THE PLOT OF THE PERIOD:\n\nPress ENTER...\n"
    msg12a: .ASCIZ  "\n\n\nTHIS IS YOUR GAIN:\n\n&gt;&gt;&gt;   %d.%02d$  &lt;&lt;&lt;Press ENTER to exit the program...\n"
    msg12b: .ASCIZ  "\n\n\nTHIS IS YOUR LOSS:\n\n&gt;&gt;&gt;   %d.%02d$  &lt;&lt;&lt;\nPress ENTER to exit the program...\n"
   
   

.ALIGN 2

.SECT .BSS

!   -----------------------------------------------------------------
! FINANCIAL DATA

    halfStd: .SPACE 2!  100                         ! To use in computation of gaussian, precomputed element
    mean: .SPACE 2  ! 2400                          ! reqStd*48/4
    drift: .SPACE 2! 50                                     ! Base daily drift of asset: 0.25%*basePct = 50
    reqStd: .SPACE 2!                                       ! Daily standard deviation of asset: 1%*basePct = 200
   
    rateR: .SPACE 2! 50                                 ! Base rate of return
!   -----------------------------------------------------------------
! RANDOMNESS GENERATION

    gaussCount: .SPACE 2                                ! Where to put next gaussian

    chaos3:  .SPACE 2                                       ! Seed components
    chaos2:  .SPACE 2      
    chaos1:  .SPACE 2      

    seed1:  .SPACE  2                                       ! seeds obtained by reordering components
    seed2:  .SPACE  2      
    seed3:  .SPACE  2

   

</pre>

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<pre>! This file contains constants used along the program.
! No interaction is ever expected between the user and these values.
! The parameters the user is allowed to tweak (for debugging or usage)
!   are grouped in usrPrms.h

!   ######################################
! SYSTEM AND LIBRARY CALLS

_EXIT      =      1
_GETCHAR   =    117
_SPRINTF   =    121
_PRINTF    =    127

 !  ######################################
 ! OTHER CONSTANTS
 TRUE = 1
 FALSE = 0
 
 ZEROINT = 0
 _HUNDRED = 100
 
!   ######################################
!   PROGRAM CONSTANTS

!   -----------------------------------------------------------------
!   SEQUENCES
_nSeq = 48                                          !   Number of variables in a generated uniform sequence
                                                                !   Should match the gaussian generator
                                                                !   To be changed to obtain longer uniform sequences
                                                                !   DO NOT CHANGE: the formulas depend on it
                                                                !           In case it is changed, halfStd has
                                                                !           to be changed accordingly with the squared-root
                                                                !           formula in series.s


!   -----------------------------------------------------------------
!   MATH
  _pcFier = 10000                               ! DO NOT CHANGE, used to set drift and Std percentages
 
 
!   -----------------------------------------------------------------
!   LOOPS

 ! MONTECARLO
    !   The Montecarlo trajectories amount to H*L
    ! Neither should exceed 16 bit unsigned
    ! Neither should exceed 32 bit unsigned, when multiplied by m_gauss
 _hMcCount = 20
 _lMcCount = 50
 
 ! PLOT
 NOP1 = 1000    ! Higher and lower parts of the waiting cycles for displaying Mc Plots
 NOP2 = 32000
 MAXMCPLT = 20  ! Total number of Montecarlo plots to display  
 

 
.SECT .TEXT
.SECT .DATA
.SECT .BSS</pre>

OPTION BEHAVIOR: THE OPTION PAYS THE DIFFERENCE BETWEEN THE UNDERLYING ASSET AND THE STRIKE IF IT IS IN THE MONEY, ZERO OTHERWISE. THERE ARE TWO KNOCK-OUT BARRIERS, A CAP AND A FLOOR: IF THE ASSET REACHES A BARRIER, THE PRICE IS FIXED UNTIL EXPIRATION.


PROGRAM DESCRIPTION:

Whenever possible, multiplications are done before divisions, in order to contain remainder approximations.

The user helps generating 3 initial numbers by keeping the Enter key pressed for a while (too small a time is not allowed). The lowest binary digits of those initial numbers form the basis for new numbers. Three different combinations of those basis are assembled to form 3 different numbers, which are less predictable than the original ones. These new numbers are 3 random seeds for 3 Linear Congruential Generators. Three sequences are thus generated: they contain uniform pseudo-random variables. The 3 sequences interact to generate one longer-period sequence (still uniforms). This one is used as a source of randomness for all the simulations. Next: 48 uniform variables are used at a time to yeld an approximated gaussian-distributed random variable, relying on the Central Limit theorem. The number 48 is a convenient number, it being: 2 squared, times 12. Still, it produces better gaussians than 12. 12 is related to the uniform distribution standard deviation; 4 saves us a square-root computation, which would complicate matters in an environment where floating-point arithmetic is not available. The gaussian variable is appropriately standardized and scaled (the values must fit in the registers) and used to form a Geometric Brownian Motion for the prices of the asset. Then barriers are applied, limiting the asset prices. A payoff is computed, relative to a strike price. Using Montecarlo, many payoffs are averaged and discounted to price the derivative. Some of the asset trajectories are shown in an animated plot, in the text-based console. Prices are scaled and matched to a row number. If the columns allowed are fewer than the whole trajectory, the plot is split into as many parts as needed. The trajectory is rescaled for every example, so that each time the maximum and minimum values are placed on the upper and lower rows of the plot. The strike price is shown as a heavy line: ======

 

 

 

 

 

 

 


PARAMETERS FOR THE PROGRAM

USER MODIFIABLE PARAMETERS [usrPrms.h] file: The first section of the file contains the parameters that determine the asset trajectory in time and the behavior of the derivative. The user can modify them. _days: the number of days the simulation will cover. E.g. Tn = 252 _startPr: price of the asset in T0. It is also the basis for other transformations. 20000 performs better in divisions (smaller remainders), 10000 is nicer _bpDrift: drift of the asset, expressed in basis points, relative to the prices of the GBM _bpReqStd: the standard deviation which the simulator is required to generate for the asset _put: whether the option is a put or a call _strike: the strike price _cap: the upper barrier _floor: the lower barrier

DEBUG AND PROGRAM: Parameters used for debugging and fine-tuning the program. _nRows, _nCols: rows and columns to display the plot. _dbgSd1, _dbgSd2, _dbgSd3: random seeds used to bypass the user-generation section.

CONSTANTS [consts.h] file: This file should need no modifications. It is worth mentioning the LOOPS part. Two variables are used to overcome the 16-bit constraint on the CX register. _hMcCount * _lMcCount is the number of trajectories Montecarlo runs on. NOP1 * NOP2 is the number of cycles the program skips between the demonstrative plots.


RUN AS: ./s88 main

LINK AS: ./as88 main prFuncs series genrand vars mtCarlo prTraj

Note: traduit automatiquement en français.