By looking again at multiple windows every time you lose quite a bit of time...

For the simple MA, the seemingly most common way is to compute the first value, and then compute the MA values incrementally, as in the following.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 

exception NotEnoughData

let SimpleMovingAverage periods data =
  if periods <= 0 then invalid_arg "periods <= 0"
  let len = Array.length data 
  if len < periods then raise NotEnoughData
  let coeff = 1.0 / float periods
  [|let acc = ref 0.0
    for i in 0 .. periods - 1 do
      acc := !acc + coeff * data.[ i ]
    yield !acc
    //compute the following values incrementally
    for i in periods .. len - 1 do
     let delta = data.[ i ] - data.[ i - periods ]
     do acc := !acc + coeff * delta
     yield !acc
  |]

Most often in TA algorithms, since the last value of an indicator depends on values n bars ago, I suppose you'll probably use imperative idioms...

By on 12/21/2008 3:59 PM ()

Is something like the following what you are looking for?

1
2
let inline avg days =
    Seq.map (Seq.take days >> Seq.average)

The "inline" is necessary to allow it to work over generic types.

Example of using with a list of lists of values:

1
2
3
4
5
let input = [ [ 1;2;3;4 ]; [4;3;2;1]; [2;3;2;3]; [3;3;3;3]; [3;3;3;4] ]
            |> Seq.map (Seq.map decimal)

input
|> avg 2

Which results in the following output:

1
2
3
4
5
6
7
8
9
val inline avg :
  int -> (seq<#seq< ^b>> -> seq< ^b>)
    when  ^b : (static member ( + ) :  ^b *  ^b ->  ^b) and
          ^b : (static member DivideByInt :  ^b * int ->  ^b) and
          ^b : (static member get_Zero : ->  ^b)

val input : seq<seq<decimal>>> 

val it : seq<decimal> = seq [1.5M; 3.5M; 2.5M; 3M; ...]> 
By on 12/20/2008 11:25 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper