Skip to content

Commit e3f5fab

Browse files
committed
Add functions definition
1 parent aa9d297 commit e3f5fab

3 files changed

Lines changed: 365 additions & 1 deletion

File tree

src/TALib.NETCore/Function.cs

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
using System;
2+
using System.Linq;
3+
using System.Reflection;
4+
5+
namespace TALib
6+
{
7+
public sealed class Function
8+
{
9+
private const string LookbackSuffix = "Lookback";
10+
private const string InPrefix = "in";
11+
private const string OutPrefix = "out";
12+
private const string OptInPrefix = "optIn";
13+
private const string GeneralRealParam = "Real";
14+
private const string BegIdxParam = "BegIdx";
15+
private const string NbElementParam = "NbElement";
16+
17+
internal Function(string name, string description, string group, string inputs, string options, string outputs)
18+
{
19+
Name = name;
20+
Description = description;
21+
Group = group;
22+
Inputs = inputs.Split('|');
23+
Options = !String.IsNullOrEmpty(options) ? options.Split('|') : Array.Empty<string>();
24+
Outputs = outputs.Split('|');
25+
}
26+
27+
public string Name { get; }
28+
29+
public string Description { get; }
30+
31+
public string Group { get; }
32+
33+
public string[] Inputs { get; }
34+
35+
public string[] Options { get; }
36+
37+
public string[] Outputs { get; }
38+
39+
public int Lookback(params int[] options)
40+
{
41+
var method = typeof(Core)
42+
.GetMethods(BindingFlags.Static | BindingFlags.Public)
43+
.Where(mi => mi.Name.EndsWith(LookbackSuffix))
44+
.SingleOrDefault(MethodFinder) ??
45+
throw new MissingMethodException(typeof(Core).FullName, LookbackMethodName);
46+
47+
var optInParameters = method.GetParameters().Where(pi => pi.Name.StartsWith(OptInPrefix)).ToList();
48+
var paramsArray = new object[optInParameters.Count];
49+
Array.Fill(paramsArray, Type.Missing);
50+
if (options.Length == optInParameters.Count)
51+
{
52+
var defOptInParameters = Options.Select(NormalizeOptionalParameter).ToList();
53+
for (int i = 0, paramsArrayIndex = 0; i < defOptInParameters.Count; i++)
54+
{
55+
var optInParameter = optInParameters.SingleOrDefault(p => p.Name == defOptInParameters[i]);
56+
if (optInParameter != null)
57+
{
58+
if (optInParameter.ParameterType.IsEnum && optInParameter.ParameterType.IsEnumDefined(options[i]))
59+
{
60+
paramsArray[paramsArrayIndex++] = Enum.ToObject(optInParameter.ParameterType, options[i]);
61+
}
62+
else
63+
{
64+
paramsArray[paramsArrayIndex++] = options[i];
65+
}
66+
}
67+
}
68+
}
69+
70+
return (int) method.Invoke(null, paramsArray);
71+
}
72+
73+
public Core.RetCode Run(double[][] inputs, double[] options, double[][] outputs) => RunInternal(inputs, options, outputs);
74+
75+
public Core.RetCode Run(decimal[][] inputs, decimal[] options, decimal[][] outputs) => RunInternal(inputs, options, outputs);
76+
77+
private Core.RetCode RunInternal<T>(T[][] inputs, T[] options, T[][] outputs)
78+
{
79+
var method = typeof(Core)
80+
.GetMethods(BindingFlags.Static | BindingFlags.Public)
81+
.Where(mi => !mi.Name.EndsWith(LookbackSuffix))
82+
.SingleOrDefault(mi => MethodFinder(mi, typeof(T[]))) ??
83+
throw new MissingMethodException(typeof(Core).FullName, $"{Name}<{typeof(T).Name}>");
84+
85+
var optInParameters = method.GetParameters().Where(pi => pi.Name.StartsWith(OptInPrefix)).ToList();
86+
87+
var paramsArray = new object[inputs.Length + 2 + outputs.Length + 2 + optInParameters.Count];
88+
inputs.CopyTo(paramsArray, 0);
89+
paramsArray[inputs.Length] = 0;
90+
paramsArray[inputs.Length + 1] = inputs[0].Length - 1;
91+
92+
var isIntegerOutput =
93+
method.GetParameters().Count(pi => pi.Name.StartsWith(OutPrefix) && pi.ParameterType == typeof(int[])) == 1;
94+
if (isIntegerOutput)
95+
{
96+
var integerOutputs = outputs.Select(ta => ta.Select(t => (int) Convert.ChangeType(t, typeof(int))).ToArray()).ToArray();
97+
integerOutputs.CopyTo(paramsArray, inputs.Length + 2);
98+
}
99+
else
100+
{
101+
outputs.CopyTo(paramsArray, inputs.Length + 2);
102+
}
103+
104+
Array.Fill(paramsArray, Type.Missing, inputs.Length + 2 + outputs.Length + 2, optInParameters.Count);
105+
if (options.Length == optInParameters.Count)
106+
{
107+
var defOptInParameters = Options.Select(NormalizeOptionalParameter).ToList();
108+
for (var i = 0; i < defOptInParameters.Count; i++)
109+
{
110+
var paramsArrayIndex = new Index(inputs.Length + 2 + outputs.Length + 2 + i);
111+
var optInParameter = optInParameters.Single(p => p.Name == defOptInParameters[i]);
112+
if (optInParameter.ParameterType == typeof(int) || optInParameter.ParameterType.IsEnum)
113+
{
114+
var intOption = Convert.ToInt32(options[i]);
115+
if (optInParameter.ParameterType.IsEnum && optInParameter.ParameterType.IsEnumDefined(intOption))
116+
{
117+
paramsArray[paramsArrayIndex] = Enum.ToObject(optInParameter.ParameterType, intOption);
118+
}
119+
else
120+
{
121+
paramsArray[paramsArrayIndex] = intOption;
122+
}
123+
}
124+
else
125+
{
126+
paramsArray[paramsArrayIndex] = options[i]!;
127+
}
128+
}
129+
}
130+
131+
var retCode = (Core.RetCode) method.Invoke(null, paramsArray);
132+
if (isIntegerOutput && retCode == Core.RetCode.Success)
133+
{
134+
var integerOutputs = Array.ConvertAll((int[]) paramsArray[inputs.Length + 2], i => (T) Convert.ChangeType(i, typeof(T)));
135+
Array.Copy(integerOutputs, 0, outputs[0], 0, ((int[]) paramsArray[inputs.Length + 2]).Length);
136+
}
137+
138+
return retCode;
139+
}
140+
141+
private bool MethodFinder(MethodBase methodInfo)
142+
{
143+
var optInParameters = methodInfo.GetParameters().Select(pi => pi.Name);
144+
var defOptInParameters = Options.Select(NormalizeOptionalParameter);
145+
146+
return methodInfo.Name == LookbackMethodName && optInParameters.All(p => defOptInParameters.Contains(p));
147+
}
148+
149+
private bool MethodFinder(MethodBase methodInfo, Type parameterType)
150+
{
151+
var parameters = methodInfo.GetParameters()
152+
.Where(pi => pi.Name != OutPrefix + BegIdxParam && pi.Name != OutPrefix + NbElementParam)
153+
.ToList();
154+
155+
var inParameters = parameters.Where(pi => pi.Name.StartsWith(InPrefix) && pi.ParameterType == parameterType)
156+
.Select(pi => pi.Name);
157+
var outParameters = parameters
158+
.Where(pi => pi.Name.StartsWith(OutPrefix) && (pi.ParameterType == parameterType || pi.ParameterType == typeof(int[])))
159+
.Select(pi => pi.Name);
160+
var optInParameters = parameters.Where(pi => pi.Name.StartsWith(OptInPrefix)).Select(pi => pi.Name);
161+
162+
var defInParameters = Inputs.Length > 1 && Inputs.All(p => p == GeneralRealParam)
163+
? Inputs.Select((p, i) => InPrefix + p + i)
164+
: Inputs.Select(p => InPrefix + p);
165+
var defOutParameters = Outputs.Select(NormalizeOutputParameter);
166+
var defOptInParameters = Options.Select(NormalizeOptionalParameter);
167+
168+
return methodInfo.Name == Name && inParameters.SequenceEqual(defInParameters) &&
169+
outParameters.SequenceEqual(defOutParameters) && optInParameters.SequenceEqual(defOptInParameters);
170+
}
171+
172+
private string LookbackMethodName => Name + LookbackSuffix;
173+
174+
private static string NormalizeOutputParameter(string parameter) => OutPrefix + parameter.Replace(" ", String.Empty);
175+
176+
private static string NormalizeOptionalParameter(string parameter) => OptInPrefix + parameter.Replace(" ", String.Empty);
177+
}
178+
}

0 commit comments

Comments
 (0)