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
  • Share/Bookmark

Leave a Reply