Module nimFinLib

Program : nimFinLib

Status : Development

License : MIT opensource

Version : 0.2.x

Compiler : nim 0.11.3

Description : A basic library for financial calculations with Nim

Yahoo historical stock data

Yahoo additional stock data

Yahoo current stock quotes

Yahoo forex rates

Dataframe like structure for easy working with historical data and dataseries

Returns calculations

Ema calculation

Date manipulations

Data display procs

Documention was created with : nim doc nimFinLib

Project : https://github.com/qqtop/NimFinLib

Tested on : Linux

ProjectStart: 2015-06-05

ToDo : Ratios , Covariance , Correlation

Programming : qqTop

Contributors: reactorMonk

Requires : strfmt,random modules and statistics.nim

Notes : it is assumed that terminal color is black background

and white text. Other color schemes may not show all output.

For comprehensive tests and usage see nimFinT5.nim

Installation: git clone https://github.com/qqtop/NimFinLib.git

or

nimble install nimFinLib

Types

Pf* = object
  pf*: seq[Nf]                 ## pf holds all Nf type portfolios for an account
  
Pf type holds all portfolios similar to a master account portfolios are Nf objects
Nf* {.inheritable.} = object
  nx*: string                  ## nx  holds portfolio name  e.g. MyGetRichPortfolio
  dx*: seq[Df]                 ## dx  holds all stocks with historical data
  
Nf type holds one portfolio with all relevant historic stocks data
Df* {.inheritable.} = object of Nf
  stock*: string               ## yahoo style stock code
  date*: seq[string]
  open*: seq[float]
  high*: seq[float]
  low*: seq[float]
  close*: seq[float]
  vol*: seq[float]             ## volume
  adjc*: seq[float]            ## adjusted close price
  ro*: seq[Runningstat]        ## RunningStat for open price
  rh*: seq[Runningstat]        ## RunningStat for high price
  rl*: seq[Runningstat]        ## RunningStat for low price
  rc*: seq[Runningstat]        ## RunningStat for close price
  rv*: seq[Runningstat]        ## RunningStat for volume price
  rca*: seq[Runningstat]       ## RunningStat for adjusted close price
  
Df type holds individual stocks history data and RunningStat for ohlcva columns even more items may be added like full company name etc in the future items are stock code, ohlcva, rc and rca .
Qf* {.inheritable.} = object
  price*: float
  change*: float
  volume*: float
  avgdailyvol*: float
  market*: string
  marketcap*: string
  bookvalue*: float
  ebitda*: string
  dividendpershare*: float
  dividendperyield*: float
  earningspershare*: float
  week52high*: float
  week52low*: float
  movingavg50day*: float
  movingavg200day*: float
  priceearingratio*: float
  priceearninggrowthratio*: float
  pricesalesratio*: float
  pricebookratio*: float
  shortratio*: float
Qf type holds additional stock data and statistics as currently available from yahoo
Ts* {.inheritable.} = object
  dd*: seq[string]
  tx*: seq[float]
Ts type is a simple timeseries object which can hold one column of any OHLCVA data
Cf* {.inheritable.} = object
  cu*: seq[string]
  ra*: seq[float]
Cf type is a simple object to hold current currency data

Vars

tw* = getTerminalWidth()
aline* = repeat("-", tw)

Lets

NIMFINLIBVERSION* = "0.2.1"

Procs

proc timeSeries*[T](self: T; ty: string): Ts

timeseries returns a Ts type date and one data column based on ty selection input usually is a Df object and a string , if a string is in ohlcva the relevant series will be extracted from the Df object

usage exmple :

timeseries(myDfObject,"o")

this would return dates in dd and open prices in ts

proc showTimeSeries*(ats: Ts; header, ty: string; N: int)
showTimeseries takes a Ts object as input as well as a header string for the data column , a string which can be one of head,tail,all and N for number of rows to display usage :
showTimeseries(myTimeseries,myHeader,"head|tail|all",rows)

Example

# show adj. close price , 5 rows head and tail 372 days apart
var myD =initDf()
myD = getSymbol2("AAPL",minusdays(getDateStr(),372),getDateStr())
var mydT = timeseries(myD,"a") # adjusted close
echo()
showTimeSeries(mydT,"AdjClose","head",5)
showTimeSeries(mydT,"AdjClose","tail",5)
proc initPf*(): PF

initPf

init a new empty account object

var myAccount = initPf()
proc initNf*(): Nf

initNf

init a new empty portfolio object

var myETFportfolio = initNf()
proc initDf*(): Df

initDf

init stock data object

var mystockData = initDf()
proc initCf*(): Cf

initCf

init a Cf object to hold basic forex data

var myForex = initCf()
proc initTs*(): Ts

initTs

init a timeseries object

proc initPool*(): seq[Df]

initPool

init pools , which are sequences of Df objects used in portfolio building

var mystockPool = initPool()
proc getTerminalWidth*(): int

getTerminalWidth

utility to easily draw correctly sized lines on linux terminals

and get linux terminal width

for windows this currently is set to terminalwidth 80

echo "Terminalwidth : ",tw
echo aline

tw and aline are exported but of course you also can do

var mytermwidth = getTerminalWidth()
echo repeat("*",mytermwidth)

in case you want to use another line building char

proc decho*(z: int)

decho

blank lines creator

decho(10)

to create 10 blank lines

proc getCurrentQuote*(stcks: string): string

getCurrentQuote

gets the current price/quote from yahoo for 1 stock code

proc buildStockString*(apf: Nf): string

buildStockString

Produce a string of one or more stock codes coming from a Nf object

proc buildStockString*(adf: seq[Df]): string

buildStockString

Produce a string of one or more stock codes coming from a pool Df object

proc showCurrentIndexes*(idxs: string) {.discardable.}

showCurrentIndexes

callable display routine for currentIndexes

proc showCurrentIndexes*(adf: seq[Df]) {.discardable.}

showCurrentIndexes

callable display routine for currentIndexes with a pool object passed in

proc showCurrentStocks*(apf: Nf) {.discardable.}

showCurrentStocks

callable display routine for currentStocks with Nf portfolio object passed in

showCurrentStocks(myAccount.Portfolio[0])

This means get all stock codes of the first portfolio in myAccount

Note : Yahoo servers maybe down sometimes which will make this procs fail.

Just wait a bit and try again. Stay calm ! Do not panic !

for full example see nimFinT5.nim

proc showCurrentStocks*(stcks: string) {.discardable.}

showCurrentStocks

callable display routine for currentStocks with stockstring passed in

showCurrentStocks("IBM+BP.L+0001.HK")
decho(2)

Note : Yahoo servers maybe down sometimes which will make this procs fail.

Just wait a bit and try again. Stay calm ! Do not panic !

proc day*(aDate: string): string

day

get day substring from a yyyy-MM-dd date string

Format dd

proc ymonth*(aDate: string): string

ymonth

yahoo month starts with 00 for jan

Format MM

not exported and only used internally for yahoo url setup

proc month*(aDate: string): string

month

get month substring from a yyyy-MM-dd date string

Format MM

proc year*(aDate: string): string

year

get year substring from a yyyy-MM-dd date string

Format yyyy

proc validdate*(adate: string): bool
proc intervalsecs*(startDate, endDate: string): float
interval procs returns time elapsed between two dates in secs,hours etc.
proc intervalmins*(startDate, endDate: string): float
proc intervalhours*(startDate, endDate: string): float
proc intervaldays*(startDate, endDate: string): float
proc intervalweeks*(startDate, endDate: string): float
proc intervalmonths*(startDate, endDate: string): float
proc intervalyears*(startDate, endDate: string): float
proc compareDates*(startDate, endDate: string): int
proc sleepy*[T: float | int](s: T)
proc plusDays*(aDate: string; days: int): string

plusDays

adds days to date string of format yyyy-MM-dd or result of getDateStr()

and returns a string of format yyyy-MM-dd

the passed in date string must be a valid date or an error message will be returned

proc minusDays*(aDate: string; days: int): string

minusDays

subtracts days from a date string of format yyyy-MM-dd or result of getDateStr()

and returns a string of format yyyy-MM-dd

the passed in date string must be a valid date or an error message will be returned

proc getSymbol2*(symb, startDate, endDate: string): Df

getSymbol2

the work horse proc for getting yahoo data in csv format

and then to parse into a Df object

proc getSymbol3*(symb: string): Qf

getSymbol3

additional data as provided by yahoo for a stock

data returned is inside an Qf object with following fields and types

the reason for string types in marketcap and ebitda is yahoo returning

numbers shortened with B for billions etc.

not all data may be available for stocks or even maybe incorrect.

so use with care.

price* : float

change* : float

volume* : float

avgdailyvol* : float

market* : string

marketcap* : string

bookvalue* : float

ebitda* : string

dividendpershare* : float

dividendperyield* : float

earningspershare* : float

week52high* : float

week52low* : float

movingavg50day* : float

movingavg200day* : float

priceearingratio* : float

priceearninggrowthratio* : float

pricesalesratio* : float

pricebookratio* : float

shortratio* : float

proc showHistData*(adf: Df; n: int)

showhistData

Show n recent rows historical stock data

proc showHistData*(adf: Df; s: string; e: string)

showhistData

show historical stock data between 2 dates

dates must be of format yyyy-MM-dd

proc last*[T](self: seq[T]): T

Various data navigation routines

first,last,head,tail

last means most recent row

proc first*[T](self: seq[T]): T
first means oldest row
proc tail*[T](self: seq[T]; n: int): seq[T]
tail means most recent rows
head means oldest rows
proc lagger*[T](self: T; days: int): T

lagger

often we need a timeseries off by x days

this functions provides this

proc dailyReturns*(self: seq[float]): seq

dailyReturns

daily returns calculation gives same results as dailyReturns in R / quantmod

proc showDailyReturnsCl*(self: Df; N: int)

showdailyReturnsCl

display returns based on close price

formated output to show date and returns columns

proc showDailyReturnsAdCl*(self: Df; N: int)

showdailyReturnsAdCl

returns based on adjusted close price

formated output to only show date and returns

proc sumDailyReturnsCl*(self: Df): float

sumdailyReturnsCl

returns sum based on close price

proc sumDailyReturnsAdCl*(self: Df): float

sumdailyReturnsAdCl

returns sum based on adjc

proc statistics*(x: Runningstat)

statistics

display statistsics output of a runningstat object

proc showStatistics*(z: Df)

showStatistics

shows all statistics from a Df objects ohlcva columns

proc showStatisticsT*(z: Df)

showStatisticsT

shows all statistics from a Df objects ohlcva columns

transposed display , needs full terminal width

proc ema*(dx: Df; N: int): Ts

ema

exponential moving average based on close price

returns a Ts object loaded with date,ema pairs

calling with Df object and number of days for moving average

results match R quantmod/TTR

proc showEma*(emx: Ts; N: int)

showEma

convenience proc to display ema series with dates

input is a ema series Ts object and rows to display

latest data is on top

proc getCurrentForex*(curs: seq[string]): Cf

getCurrentForex

get the latest yahoo exchange rate info for a currency pair

e.g EURUSD , JPYUSD ,GBPHKD

var curs = getCurrentForex(@["EURUSD","EURHKD"])
echo()
echo "Current EURUSD Rate : ","{:<8}".fmt(curs.ra[0])
echo "Current EURHKD Rate : ","{:<8}".fmt(curs.ra[1])
echo()
proc showCurrentForex*(curs: seq[string])

showCurrentForex

a convenience proc to display exchange rates

showCurrentForex(@["EURUSD","GBPHKD","CADEUR","AUDNZD"])
decho(3)
proc showDfTable*(apfdata: Nf)

showDfTable

a convenience prog to display the data part of a Nf object

for usage example see nimFinT3

proc showQftable*(a: Qf)

showQftable

shows all items of a Qf object

proc presentValue*[T](FV: T; r: T; m: int; t: int): float

presentValue

Present Value Calculation for a Lump Sum Investment

Future Value (FV)
is the future value sum of an investment that you want to find a present value for
Number of Periods (t)
commonly this will be number of years but periods can be any time unit. Use int or floats for partial periods such as months for example, 7.5 years is 7 yr 6 mo.
Interest Rate (R)
is the annual nominal interest rate or "stated rate" in percent. r = R/100, the interest rate in integer or floats
Compounding (m)
is the number of times compounding occurs per period. If a period is a year then annually=1, quarterly=4, monthly=12, daily = 365, etc.
Rate (i)
i = (r/m); interest rate per compounding period.
Total Number of Periods (n)
n = mt; is the total number of compounding periods for the life of the investment.
Present Value (PV)
the calculated present value of your future value amount

From http://www.CalculatorSoup.com - Online Calculator Resource.

var FV : float = 10000
var PV : float = 0.0
var r  : float = 0.0625
var m  : int   = 2
var t  : int   = 12

PV = presentValue(FV,r,m,t)
echo PV
proc presentValue*(FV: float; r: float; m: float; t: float): float

presentValue

Present Value Calculation for a Lump Sum Investment

PV = presentValue(FV,0.0925,2.0,12.0)
echo PV
proc presentValueFV*(FV: float; i: float; n: int): float

presentValueFV

the present value of a future sum at a periodic interest rate i where n is the number of periods in the future.

PV = presentValueFV(FV,0.0625,10)
echo PV
proc presentValueFV*(FV: float; i: float; n: float): float
PV = presentValueFV(FV,0.0625,20.5)
echo PV
proc rainbow*(astr: string)

rainbow

random multi colored string

rainbow("Sparkling string display !")
decho(2)
proc handler*() {.noconv.}

handler

experimental

this runs if ctrl-c is pressed

and provides some feedback upon exit

import nimFinLib
# get the latest delayed quotes for your stock
# press ctrl-c to exit
# setControlCHook(handler)    # auto registered exit handler
while true :
   showCurrentStocks("IBM+AAPL+BP.L")
   sleepy(5)
proc logisticf*(z: float): float

logisticf

maps the input z to an output between 0 and 1

proc logisticf_derivative*(z: float): float

logisticf_derivative

returns derivative of logisticf for gradient solutions

proc doFinish*()

doFinish

a end of program routine which displays some information

can be changed to anything desired

Templates

template msgg*(code: stmt): stmt {.immediate.}
msgX templates convenience templates for colored text output the assumption is that the terminal is white text and black background naming of the templates is like msg+color so msgy => yellow msg+color+b turns on the bright flag
msgg() do : echo "How nice, it's in green"
template msggb*(code: stmt): stmt {.immediate.}
msggb
msggb() do : echo "How nice, it's in bright green"
template msgy*(code: stmt): stmt {.immediate.}
template msgyb*(code: stmt): stmt {.immediate.}
template msgr*(code: stmt): stmt {.immediate.}
template msgrb*(code: stmt): stmt {.immediate.}
template msgc*(code: stmt): stmt {.immediate.}
template msgcb*(code: stmt): stmt {.immediate.}
template msgw*(code: stmt): stmt {.immediate.}
template msgwb*(code: stmt): stmt {.immediate.}
template msgb*(code: stmt): stmt {.immediate.}
template hdx*(code: stmt): stmt {.immediate.}

hdx

hdx is used for headers to make them stand out

it puts the text between 2 horizontal lines

template withFile*(f: expr; filename: string; mode: FileMode; body: stmt): stmt {.
    immediate.}

withFile

file open close utility template

let curFile="notes.txt"    # some file
withFile(txt, curFile, fmRead):
    while true :
        try:
           stdout.writeln(txt.readLine())   # do something with the lines
        except:
           break
echo()