This is part of a series on technical analysis indicators in F#, based on the multi-language TA-Lib.
Quick disclaimer : some of these indicators are not verified.
Reflection : retrieve information on the studies
In this part, we show how to use reflection to fetch the metadata attributes we have described in the first part of the technical analysis series.
namespace Trading.Chart open System open System.Reflection open Microsoft.FSharp.Reflection open Trading.Studies // // Store info // module Reflection = type ParamInfo(p:ParameterInfo) = let name = let arr = p.GetCustomAttributes(typeof<DisplayNameAttribute>, false) if arr.Length = 0 then p.Name else (arr.[0] :?> DisplayNameAttribute).Name let defaultValue = let arr = p.GetCustomAttributes(typeof<DefaultValueAttribute>, false) if arr.Length = 0 then None else Some (arr.[0] :?> DefaultValueAttribute) let isBool = let arr = p.GetCustomAttributes(typeof<BoolAttribute>, false) arr.Length <> 0 let numAttr = let arr = p.GetCustomAttributes(typeof<NumericAttribute>, false) if arr.Length = 0 then None else Some (arr.[0] :?> NumericAttribute) let allPositiveAttr = let arr = p.GetCustomAttributes(typeof<AllPositiveAttribute>, false) arr.Length <> 0 member x.Name = name member x.Type = p.ParameterType.Name member x.Position = p.Position member x.IsBool = isBool member x.NumericAttribute = numAttr member x.AllPositiveAttribute = allPositiveAttr override x.ToString() = sprintf "{Name=%s; Type=%s; Position:%d; IsBool:%A; IsNumeric:%s}" x.Name x.Type x.Position x.IsBool ( match x.NumericAttribute with | None -> match x.Type.ToLower() with | "int32" | "double" -> "yes;" | _ -> "no;" | Some attr -> let min = if attr.MinValue = "nan" then "" else sprintf "min:%s; " attr.MinValue let max = if attr.MaxValue = "nan" then "" else sprintf "max:%s; " attr.MaxValue let step = if attr.Step = "nan" then "" else sprintf "step:%s;" attr.Step let np = if (min.Length > 0 || max.Length > 0 || step.Length > 0) then sprintf " NumericParams:{%s%s%s}" min max step else "" sprintf "yes;%s" np ) type StudyInfo = { Group : string Title : string Description : string DoesOverlay : bool HasMultipleInputSeries : bool Parameters : ParamInfo[] OutputTypes : string[] OutputSeriesNames : string[] } with static member create g t desc d multipleSeries p ot series = { Group = g Title = t Description = desc DoesOverlay = d HasMultipleInputSeries = multipleSeries Parameters = p OutputTypes = ot OutputSeriesNames = series } //==================================================================== // // Extract the meta information from studies within the // assembly containing "Trading.Studies.TradingStudyAttribute" // //==================================================================== let getMetainfo (m:MethodInfo) = let ps = m.GetParameters() |> Array.map (fun p -> new ParamInfo(p)) let outTypes = let ty = m.ReturnType if FSharpType.IsTuple ty then FSharpType.GetTupleElements ty |> Array.map (fun ty -> ty.Name) else [|ty.Name|] let group = let arr = m.GetCustomAttributes((typeof<GroupAttribute>),false) if arr.Length = 0 then "" else (arr.[0] :?> GroupAttribute).Group let title = let arr = m.GetCustomAttributes((typeof<TitleAttribute>),false) if arr.Length = 0 then "" else (arr.[0] :?> TitleAttribute).Title let description = let arr = m.GetCustomAttributes((typeof<DescriptionAttribute>),false) if arr.Length = 0 then "" else (arr.[0] :?> DescriptionAttribute).Description let hasMultipleSeries = let arr = m.GetCustomAttributes((typeof<MultipleInputSeriesAttribute>),false) arr.Length <> 0 let seriesNames = let arr = m.GetCustomAttributes((typeof<OutputSeriesNamesAttribute>),false) if arr.Length = 0 then [|"output"|] else (arr.[0] :?> OutputSeriesNamesAttribute).Series let doesOverlay = let arr = m.GetCustomAttributes((typeof<OverlayAttribute>),false) arr.Length <> 0 StudyInfo.create group title description doesOverlay hasMultipleSeries ps outTypes seriesNames let isStudy (m:MemberInfo) = (m.GetCustomAttributes((typeof<TradingStudyAttribute>),false)).Length <> 0 && (m :? MethodInfo) let getStudiesInfo() = typeof<Trading.Studies.TradingStudyAttribute>.Assembly.GetTypes() |> Array.filter FSharpType.IsModule |> Array.map (fun m -> m.GetMembers() |> Array.filter isStudy ) |> Array.concat |> Array.map (fun m -> (m.Name, getMetainfo (m :?> MethodInfo))) |> Map.ofArray
Example use
do for KeyValue(name, info) in Trading.Chart.Reflection.getStudiesInfo() do printfn "%s : %A" name info