Generic Fixed Income language (In Erlang)

Trying to write my own implementation of the famous paper of Simon Peyton
“How to Write financal contract”
in Erlang

Everything  here is free in hope that someone will be interested and will enhance it.

-module(bLangParser).
-compile(export_all).
-record(contract,{name,starting_date,maturity,rate,fixed_percantage}).
-define(rec_info(T,R),lists:zip(record_info(fields,T),tl(tuple_to_list(R)))).
readFile(FileName)->
    {ok,A} = file:consult(FileName),
    readContract(hd(A),1,size(hd(A))).
readContract(A,N,Max) ->
    if (N =< Max )->
                Elem = element(N,A),
                case is_atom(Elem) of
                    true -> readAtomicContract({Elem}),
                        readContract(A,N+1,Max);
                    false -> readAtomicContract(Elem),
                        readContract(A,N+1,Max)
                end;
             true ->
                 ok
         end.
readAtomicContract(A) ->
    NameOrNown = element(1,A),
    IsContract = isValidContract(NameOrNown),
    case IsContract of
        true -> io:format("I wil call read contract ~n"),
                makeContract(A);
        false ->
            IsNown = isValidNown(NameOrNown),
            case IsNown of
                true -> io:format("I will write logic for nown ~n");
                false -> io:format("Entered something that is not thougth of yet!! ~n")
            end
    end.
isValidContract(Name)->
    lists:member(Name,[zcb]).
isValidNown(Name) ->
    lists:member(Name,['and']).
makeContract(C) ->
        Type = element(1,C),
        case Type of
            zcb ->
        io:format("I will make zero coupon bond now ~p~n",[C]);
        _else -> io:format("nothing")
    end.

 -record(r,{name,starting_date,maturity,rate,fixed_percantage}).

 go() -> ?rec_info(contract,#contract{}).

This is the input for this module

{'and',{zcb , {starting_date,{2010,10,9}},{maturity ,{2016,10,1}},{rate,{fixed_percantage ,5}}}}.

Core Date Module for handling business day convention

thirdWednesday({Y,M,_D}) ->
 % Algorithm suggested by Mark Ransom at stack overflow quesion 5421972
 DayNum = calendar:day_of_the_week({Y,M,1}),
 SubNum = 4-DayNum , % Wednesday = 3
 if (SubNum < 0 ) ->
 {Y,M,SubNum + 21} ;
 true ->
 {Y,M,SubNum + 14}
 end.</pre>
%Returns a factor that needs to be multiplied for day count convention adjustment
% last two arguments are tenor with F signifying From and T signifying To
%used a paper from net Named OpenGamma Interest rate instrument and Market convention guide. Can't gurrantee the credibility
conventions(Catom,{Fy,Fm,Fd},{Ty,Tm,Td}) ->
 case Catom of
% space left for some comment
 '30/360' ->
 (360 * ( Fy - Ty ) + 30 * ( Fm - Tm ) + ( Fd - Td ) ) / 360;

% space left for some comment
 'act/360' ->
 (Td-Fd)/360;

% space left for some comment
 'act/365_fixed' ->
 (Td-Fd)/365;
% space left for some comment

'act/act_isda' ->

% space left for some comment
 IsLeapFrom = calendar:is_leap_year(Fy),
 case
 IsLeapFrom of
 true -> DF = 366;
 false -> DF = 365
 end,

% space left for some comment
 case Fy of
 Ty ->
 day_difference({Fy,Fm,Fd},{Fy,12,31}) / DF + day_difference({Ty,01,01},{Ty,Tm,Td}) / DF;
 true -> % not same hence find for To year as well
 IsLeapTo = calendar:is_leap_year(Ty),
 case
 IsLeapTo of
 true -> DT = 366;
 false -> DT = 365
 end,
 day_difference({Fy,Fm,Fd},{Fy,12,31}) / DF + day_difference({Ty,01,01},{Ty,Tm,Td}) / DT
 end;

% space left for some comment
 'business/252' ->
 io:stream("For This functionality I need business calendar which is still in progress")
 end.

% space left for some comment
day_difference(From,To) ->
 calendar:date_to_gregorian_days(To) - calendar:date_to_gregorian_days(From) + 1.
<pre>

Now Some unit Tests

</pre>
-module(dateUtils_tests).
-include_lib("eunit/include/eunit.hrl").

day_difference_test()->
 365 =dateUtils:day_difference({2012,1,1},{2012,12,31}).
conventions_test()->
 0.15846994535519127 = dateUtils:conventions('act/act_isda',{2000,01,01}, {2000,02,28}),
 0.00273224043715847= dateUtils:conventions('act/act_isda',{2000,02,28}, {2000,02,29}),
 0.00546448087431694 = dateUtils:conventions('act/act_isda',{2000,02,28}, {2000,03,01}),
 0.00273224043715847= dateUtils:conventions('act/act_isda',{2000,02,29}, {2000,03,01}),
 0.997716894977169 = dateUtils:conventions('act/act_isda',{2000,03,01}, {2001,03,01}),
 0.5 = dateUtils:conventions('act/act_isda',{2000,06,15}, {2000,12,15}),
 5.002283105022832 = dateUtils:conventions('act/act_isda',{1999,03,01}, {2004,03,01}),
 6.0 = dateUtils:conventions('act/act_isda',{1999,03,01}, {2005,03,01}),
 % 0.495890411 = dateUtils:conventions('act/act_isda',{1999,01,15}, {1999,07,15}),
 % 0.002739726 = dateUtils:conventions('act/act_isda',{2001,01,30}, {2001,01,31}),
 % 0.252054795 = dateUtils:conventions('act/act_isda',{2001,05,31}, {2001,08,31}),
 % 0.00273224 = dateUtils:conventions('act/act_isda',{2000,02,28}, {2000,02,29}),
 % 1.002298076 = dateUtils:conventions('act/act_isda',{1999,02,28}, {2000,02,29}),
 % 0.997701924 = dateUtils:conventions('act/act_isda',{2000,02,29}, {2001,02,28}),
 1.0 = dateUtils:conventions('act/act_isda',{2001,02,28}, {2002,02,28}),
 % 0.249315068 = dateUtils:conventions('act/act_isda',{2001,05,31}, {2001,08,30}),
 % 0.252054795 = dateUtils:conventions('act/act_isda',{2001,05,30}, {2001,08,30}),
 4.0 = dateUtils:conventions('act/act_isda',{2000,02,29}, {2004,02,29}).
round(Number, Precision) ->
 P = math:pow(10, Precision),
 round(Number * P) / P.
 %04 0.252054795 0.249315068 1 0.997701924 1.002298076 0.00273224 0.252054795 0.002739726 0.495890411 6 5.002290591 0.5 0.997709409 0.00273224 0.005464481 0.00273224 .158469945
<pre>
Advertisements