{-# LANGUAGE OverloadedStrings , BangPatterns , MultiWayIf , LambdaCase , TemplateHaskell #-} module Main where import Control.Monad ( void ) import qualified Graphics.UI.FLTK.LowLevel.FL as FL import Graphics.UI.FLTK.LowLevel.Fl_Types import Graphics.UI.FLTK.LowLevel.FLTKHS as FL import Graphics.UI.FLTK.LowLevel.Fl_Enumerations import Control.Lens import Graphics.Rendering.Chart import Graphics.Rendering.Chart.Grid import Graphics.Rendering.Chart.Easy as Ch import Graphics.Rendering.Chart.Backend.FLTKHS -- haskell black scholes (see http://www.espenhaug.com/black_scholes.html) blackScholesCall :: Double -> Double -> Double -> Double -> Double -> Double blackScholesCall s x t r v = s * normcdf d1 - x * exp (-r * t) * normcdf d2 where d1 = (log (s / x) + (r + v * v / 2) * t) / (v * sqrt t) d2 = d1 - v * sqrt t normcdf :: Double -> Double normcdf x | x < 0 = 1 - w | otherwise = w where w = 1.0 - 1.0 / sqrt (2.0 * pi) * exp (-l * l / 2.0) * ( a1 * k + a2 * (k ** 2) + a3 * (k ** 3) + a4 * (k ** 4) + a5 * (k ** 5) ) k = 1.0 / (1.0 + 0.2316419 * l) l = abs x a1 = 0.31938153 a2 = -0.356563782 a3 = 1.781477937 a4 = -1.821255978 a5 = 1.330274429 -- Construct a single chart for the grid bsChart :: Double -> Double -> Double -> Layout Double Double bsChart t r v = execEC $ do layout_y_axis . laxis_generate .= scaledAxis def (-10, 80) plot $ line "" [[ (s, blackScholesCall s 100 0.001 r v) | s <- ss ]] plot $ line lbl [[ (s, blackScholesCall s 100 t r v) | s <- ss ]] where ss = [50, 51 .. 150] lbl = "t = " ++ show t ++ ", r = " ++ show r -- Construct a grid of charts, with a single title accross the top grid = title `wideAbove` aboveN [ besideN [ layoutToGrid (bsChart t r v) | t <- ts ] | r <- rs ] where ts = [1, 2, 5] rs = [0.05, 0.10, 0.20] v = 0.10 title = setPickFn nullPickFn $ label ls HTA_Centre VTA_Centre "Black Scholes Option Values" ls = def { _font_size = 15, _font_weight = FontWeightBold } drawChart :: Ref Widget -> IO () drawChart widget = do rectangle' <- getRectangle widget withFlClip rectangle' $ void $ renderToWidget widget $ fillBackground def $ gridToRenderable $ grid main :: IO () main = do let width = 800 height = 600 window' <- doubleWindowNew (Size (Width width) (Height height)) Nothing Nothing begin window' widget' <- widgetCustom (FL.Rectangle (Position (X 0) (Y 0)) (Size (Width width) (Height height)) ) Nothing drawChart defaultCustomWidgetFuncs end window' showWidget window' void FL.run