This is the first part of a series on technical analysis indicators in F#.
We will define the basic object holding the data series which will be used to compute the indicators. We will also describe some functions to check the integrity of the said data (and which will be useful when defining the indicators).
Quick disclaimer : many of these indicators are not verified. And the code may very well be slower than in TA-Lib. The point was only to see how easy it was to use F# to program them, regardless of the imperative or functional programming style.
PriceSeries.fs
namespace TechnicalAnalysis.Data
open System
type PriceSeries =
{ Date : DateTime[]
Open : float[]
High : float[]
Low : float[]
Close : float[]
Volume : float[]
AdjustedClose: float[]
}
static member create n =
{ Date = Array.zeroCreate n
Open = Array.zeroCreate n
High = Array.zeroCreate n
Low = Array.zeroCreate n
Close = Array.zeroCreate n
Volume = Array.zeroCreate n
AdjustedClose = Array.zeroCreate n
}
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module PriceSeries =
let create n =
{ Date = Array.zeroCreate n
Open = Array.zeroCreate n
High = Array.zeroCreate n
Low = Array.zeroCreate n
Close = Array.zeroCreate n
Volume = Array.zeroCreate n
AdjustedClose = Array.zeroCreate n
}
let rec private areDatesInvalidAux dates i found =
if found then true
elif i >= Array.length dates then found
else
areDatesInvalidAux dates (i+1) (dates.[i] < dates.[i-1])
let checkDates dates =
if Array.length dates > 1 && areDatesInvalidAux dates 1 false then
invalidArg "dates" "dates are not sorted"
let checkSameLength a b =
if Array.length a <> Array.length b then
invalidArg "input arrays" "input arrays have different lengths"
let checkHighLow high low =
checkSameLength high low
for i in 0 .. high.Length - 1 do
if high.[i] < low.[i] then
let reason = sprintf "high < low at index %d" i
invalidArg "high" reason
let checkHighLowClose high low c =
checkSameLength high low
checkSameLength high c
for i in 0 .. Array.length high - 1 do
if c.[i] > high.[i] then
let reason = sprintf "open > high at index %d" i
invalidArg "high" reason
if low.[i] > c.[i] then
let reason = sprintf "low > open at index %d" i
invalidArg "low" reason
let checkOpenHighLowClose o high low c =
checkSameLength high low
checkSameLength high o
checkSameLength high c
for i in 0 .. Array.length high - 1 do
if o.[i] > high.[i] then
let reason = sprintf "open > high at index %d" i
invalidArg "high" reason
if low.[i] > o.[i] then
let reason = sprintf "low > open at index %d" i
invalidArg "low" reason
if c.[i] > high.[i] then
let reason = sprintf "close > high at index %d" i
invalidArg "high" reason
if low.[i] > c.[i] then
let reason = sprintf "low > close at index %d" i
invalidArg "low" reason