Free cookie consent management tool by TermsFeed Policy Generator

source: branches/sluengo/HeuristicLab.Problems.TradeRules/Interpreter.cs @ 9147

Last change on this file since 9147 was 9147, checked in by gkronber, 11 years ago

changed int constants to double constants to prevent future mistakes

File size: 24.9 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using HeuristicLab.Common;
6using HeuristicLab.Core;
7using HeuristicLab.Data;
8using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
9using HeuristicLab.Parameters;
10using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
11using HeuristicLab.Problems.DataAnalysis.Symbolic;
12using HeuristicLab.Problems.DataAnalysis;
13
14namespace HeuristicLab.Problems.TradeRules
15{
16    [StorableClass]
17    [Item("Interpreter", "Represents a grammar for Trading Problems")]
18    public sealed class Interpreter : ParameterizedNamedItem, ISymbolicDataAnalysisExpressionTreeInterpreter
19    {
20        private const string CheckExpressionsWithIntervalArithmeticParameterName = "CheckExpressionsWithIntervalArithmetic";
21        private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
22        [ThreadStatic]
23        private static double [] EMAValue;
24        [ThreadStatic]
25        private static double inOut;
26        [ThreadStatic]
27        private static double meanUp;
28        [ThreadStatic]
29        private static double meanDown;
30        [ThreadStatic]
31        private static double lastRSI;
32        #region private classes
33        //This class manipulate the instructions of the stack
34        private class InterpreterState
35        {
36            private double[] argumentStack;
37            private int argumentStackPointer;
38            private Instruction[] code;
39            private int pc;
40            public int ProgramCounter
41            {
42                get { return pc; }
43                set { pc = value; }
44            }
45            internal InterpreterState(Instruction[] code, int argumentStackSize)
46            {
47                this.code = code;
48                this.pc = 0;
49                if (argumentStackSize > 0)
50                {
51                    this.argumentStack = new double[argumentStackSize];
52                }
53                this.argumentStackPointer = 0;
54            }
55
56            internal void Reset()
57            {
58                this.pc = 0;
59                this.argumentStackPointer = 0;
60            }
61
62            internal Instruction NextInstruction()
63            {
64                return code[pc++];
65            }
66            private void Push(double val)
67            {
68                argumentStack[argumentStackPointer++] = val;
69            }
70            private double Pop()
71            {
72                return argumentStack[--argumentStackPointer];
73            }
74
75            internal void CreateStackFrame(double[] argValues)
76            {
77                // push in reverse order to make indexing easier
78                for (int i = argValues.Length - 1; i >= 0; i--)
79                {
80                    argumentStack[argumentStackPointer++] = argValues[i];
81                }
82                Push(argValues.Length);
83            }
84
85            internal void RemoveStackFrame()
86            {
87                int size = (int)Pop();
88                argumentStackPointer -= size;
89            }
90
91            internal double GetStackFrameValue(ushort index)
92            {
93                // layout of stack:
94                // [0]   <- argumentStackPointer
95                // [StackFrameSize = N + 1]
96                // [Arg0] <- argumentStackPointer - 2 - 0
97                // [Arg1] <- argumentStackPointer - 2 - 1
98                // [...]
99                // [ArgN] <- argumentStackPointer - 2 - N
100                // <Begin of stack frame>
101                return argumentStack[argumentStackPointer - index - 2];
102            }
103        }
104
105        //Operation codes
106        private class OpCodes
107        {
108            public const byte Add = 1;
109            public const byte Sub = 2;
110            public const byte Mul = 3;
111
112            public const byte GT = 5;
113            public const byte LT = 6;
114
115            public const byte AND = 7;
116            public const byte OR = 8;
117            public const byte NOT = 9;
118            public const byte BOOLEAN = 10;
119
120            public const byte Average = 11;
121            public const byte MACD = 12;
122
123            public const byte Variable = 13;
124            public const byte Constant = 14;
125            public const byte ConstantInt = 16;
126            public const byte BoolConstant = 15;
127            public const byte Max = 17;
128            public const byte Min = 18;
129            public const byte Lag = 19;
130            public const byte RSI = 20;
131            public const byte EMA = 21;
132           
133
134        }
135        #endregion
136
137        #region IStatefulItem
138        public void InitializeState()
139        {
140            EvaluatedSolutions.Value = 0;
141        }
142
143        public void ClearState()
144        {
145        }
146        #endregion
147
148        private Dictionary<Type, byte> symbolToOpcode = new Dictionary<Type, byte>() {
149      { typeof(Addition), OpCodes.Add },
150      { typeof(Subtraction), OpCodes.Sub },
151      { typeof(Multiplication), OpCodes.Mul },
152      { typeof(Constant), OpCodes.Constant },
153      { typeof(BoolConstant), OpCodes.BoolConstant },
154      { typeof(ConstantInt), OpCodes.ConstantInt },
155      { typeof(GreaterThan), OpCodes.GT },
156      { typeof(LessThan), OpCodes.LT },
157      { typeof(And), OpCodes.AND },
158      { typeof(Or), OpCodes.OR },
159      { typeof(Not), OpCodes.NOT},
160      { typeof(AverageTrade), OpCodes.Average},
161      { typeof(MACD), OpCodes.MACD},
162      { typeof(RSI), OpCodes.RSI},
163      { typeof(EMA), OpCodes.EMA},
164      { typeof(Max), OpCodes.Max},
165      { typeof(Min), OpCodes.Min},
166      { typeof(Lag), OpCodes.Lag},
167      { typeof(HeuristicLab.Problems.DataAnalysis.Symbolic.Variable), OpCodes.Variable },
168    };
169
170        public override bool CanChangeName
171        {
172            get { return false; }
173        }
174        public override bool CanChangeDescription
175        {
176            get { return false; }
177        }
178
179        #region parameter properties
180        public IValueParameter<BoolValue> CheckExpressionsWithIntervalArithmeticParameter
181        {
182            get { return (IValueParameter<BoolValue>)Parameters[CheckExpressionsWithIntervalArithmeticParameterName]; }
183        }
184
185        public IValueParameter<IntValue> EvaluatedSolutionsParameter
186        {
187            get { return (IValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; }
188        }
189        #endregion
190
191        #region properties
192        public BoolValue CheckExpressionsWithIntervalArithmetic
193        {
194            get { return CheckExpressionsWithIntervalArithmeticParameter.Value; }
195            set { CheckExpressionsWithIntervalArithmeticParameter.Value = value; }
196        }
197
198        public IntValue EvaluatedSolutions
199        {
200            get { return EvaluatedSolutionsParameter.Value; }
201            set { EvaluatedSolutionsParameter.Value = value; }
202        }
203        #endregion
204
205
206       
207
208        private double Evaluate(Dataset dataset, ref int row, InterpreterState state)
209        {
210            Instruction currentInstr = state.NextInstruction();
211
212            switch (currentInstr.opCode)
213            {
214                case OpCodes.Add:
215                    {
216                        double s = Evaluate(dataset, ref row, state);
217                        for (int i = 1; i < currentInstr.nArguments; i++)
218                        {
219                            s += Evaluate(dataset, ref row, state);
220                        }
221                        return s;
222                    }
223                case OpCodes.Sub:
224                    {
225                        double s = Evaluate(dataset, ref row, state);
226                        for (int i = 1; i < currentInstr.nArguments; i++)
227                        {
228                            s -= Evaluate(dataset, ref row, state);
229                        }
230                        if (currentInstr.nArguments == 1) s = -s;
231                        return s;
232                    }
233                case OpCodes.Mul:
234                    {
235                        double p = Evaluate(dataset, ref row, state);
236                        for (int i = 1; i < currentInstr.nArguments; i++)
237                        {
238                            p *= Evaluate(dataset, ref row, state);
239                        }
240                        return p;
241                    }
242                case OpCodes.Average:
243                    {
244                        double sum = Evaluate(dataset, ref row, state);
245                        int integerValue = (int) Math.Floor(sum);
246                        if (integerValue > 100) integerValue = 100;
247                        if (row < integerValue)
248                        {
249                            string variableName = dataset.GetValue(row, 2);
250                            double inferiorValue = Convert.ToDouble(variableName);
251                            return inferiorValue/(row+1);
252                        }
253                        else
254                        {
255                            string variableName = dataset.GetValue(row, 2);
256                            double meanValue1 = Convert.ToDouble(variableName);
257                            string variableName2 = dataset.GetValue((row - integerValue), 2);
258                            double meanValue2 = Convert.ToDouble(variableName2);
259                            return (meanValue1 - meanValue2) / integerValue;
260                        }
261                    }
262                case OpCodes.MACD:
263                    {                 
264                        /*double firstMean = Evaluate(dataset, ref row, state);
265                        double secondMean = Evaluate(dataset, ref row, state);
266                        double signal = Evaluate(dataset, ref row, state);
267                        double firstEMA = 0.0;
268                        double secondEMA = 0.0;
269                        double lastFirstEMA = 0.0;
270                        double lastSecondEMA = 0.0;
271                        double macd = 0.0;
272                        double firstFactor = 0.0;
273                        double signalValue = Double.NegativeInfinity;
274                        if (row == (firstMean - 1))
275                        {
276                            string variableName = dataset.GetValue(row, 2);
277                            double meanValue1 = Convert.ToDouble(variableName);
278                            firstEMA = meanValue1 / firstMean;
279                        }
280                        if (row == (secondMean-1))
281                        {
282                            string variableName = dataset.GetValue(row, 2);
283                            double meanValue2 = Convert.ToDouble(variableName);
284                            secondEMA = meanValue2 / secondMean;
285                        }
286                        string variableName2 = dataset.GetValue(row, 1);
287                        double intValue = Convert.ToDouble(variableName2);
288                        if (row > (firstMean-1))
289                        {
290                              firstFactor = 2 / (firstMean + 1);                         
291                              firstEMA = (intValue * firstFactor) + (lastFirstEMA * (1-firstFactor));
292                        }
293                            if (row > (secondMean-1))
294                            {
295                                double secondFactor = 2 / (secondMean + 1);
296                                secondEMA = (intValue * secondFactor) + (lastSecondEMA * (1 - secondFactor));     
297                            }
298                            lastFirstEMA = firstEMA;
299                            lastSecondEMA = secondEMA;
300                            macd = firstEMA - secondEMA;
301                        if ((row < (firstMean-1)) || (row < (secondMean-1))) return 0.0;
302                        else return macd;*/
303                        return 0.0;
304
305                        //macd = firstEMA - secondEMA;
306                        //if (row == Math.Max(firstMean, secondMean)) signalValue = macd;
307                        //if (row > firstMean && row > secondMean)
308                        //{
309                        //    double factor = 2 / (signal + 1);
310                        //    signalValue = (macd * factor) + (lastSignal * (1 - factor));
311                        //}
312                        //if (!Double.IsNegativeInfinity(signalValue)) lastSignal = signalValue;
313                        //return signalValue > macd ? 1.0 : -1.0;
314                    }
315                case OpCodes.AND:
316                    {
317                        double result = Evaluate(dataset, ref row, state);
318                        for (int i = 1; i < currentInstr.nArguments; i++)
319                        {
320                            if (result > 0.0) result = Evaluate(dataset, ref row, state);
321                            else
322                            {
323                                SkipInstructions(state);
324                            }
325                        }
326                        return result > 0.0 ? 1.0 : -1.0;
327                    }
328                case OpCodes.OR:
329                    {
330                        double result = Evaluate(dataset, ref row, state);
331                        for (int i = 1; i < currentInstr.nArguments; i++)
332                        {
333                            if (result <= 0.0) result = Evaluate(dataset, ref row, state);
334                            else
335                            {
336                                SkipInstructions(state);
337                            }
338                        }
339                        return result > 0.0 ? 1.0 : -1.0;
340                    }
341                case OpCodes.NOT:
342                    {
343                        return Evaluate(dataset, ref row, state) > 0.0 ? -1.0 : 1.0;
344                    }
345
346                case OpCodes.BOOLEAN:
347                    {
348                        var booleanTreeNode = currentInstr.dynamicNode as BoolConstantTreeNode;
349                        return booleanTreeNode.Value;
350                    }
351                case OpCodes.GT:
352                    {
353                        double x = Evaluate(dataset, ref row, state);
354                        double y = Evaluate(dataset, ref row, state);
355                        if (x > y) return 1.0;
356                        else return -1.0;
357                    }
358                case OpCodes.LT:
359                    {
360                        double x = Evaluate(dataset, ref row, state);
361                        double y = Evaluate(dataset, ref row, state);
362                        if (x < y) return 1.0;
363                        else return -1.0;
364                    }
365                case OpCodes.Variable:
366                    {
367                        if (row < 0 || row >= dataset.Rows)
368                            return double.NaN;
369                        var variableTreeNode = (VariableTreeNode)currentInstr.dynamicNode;
370                        return ((IList<double>)currentInstr.iArg0)[row] * variableTreeNode.Weight;
371                    }
372                case OpCodes.EMA:
373                    {
374                        //I assume you want to calculate the EMA as defined at http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
375            //for the mean value saved at position 1 of the dataset
376            //and timevalue specifies how many days you want to include in your EMA
377            double timeValue = (int)Evaluate(dataset, ref row, state);
378
379            //get all mean values from row - timeValue up to the actual row
380            double[] meanValues = dataset.GetDoubleValues("insert variable name", Enumerable.Range(row - (int)timeValue, timeValue)).ToArray();
381
382            double EMA = meanValues[0];
383            double factor = 2.0 / (timeValue + 1.0);
384
385            for (int i = 1; i < timeValue; i++) {
386              EMA = meanValues[i] * factor + (1 - factor) * EMA;
387            }
388            return EMA;
389                    }
390                case OpCodes.Constant:
391                    {
392                        var constTreeNode = currentInstr.dynamicNode as ConstantTreeNode;
393                        return constTreeNode.Value;
394                    }
395                case OpCodes.BoolConstant:
396                    {
397                        var boolConstTreeNode = currentInstr.dynamicNode as BoolConstantTreeNode;
398                        return boolConstTreeNode.Value;
399                    }
400                case OpCodes.ConstantInt:
401                    {
402                        var constIntTreeNode = currentInstr.dynamicNode as ConstantIntTreeNode;
403                        return constIntTreeNode.Value;
404                    }
405                case OpCodes.Max:
406                    {
407                        int n = (int) Evaluate(dataset, ref row, state);
408                        double max = Double.NegativeInfinity;
409                        int i = Math.Min(n,row);
410                        while(i>=0)
411                        {
412                            int position = row - i;
413                            string variableName = dataset.GetValue(position, 1);
414                            double intValue = Convert.ToDouble(variableName);
415                            if (intValue>max) max = intValue;
416                        i--;
417                        }
418                        return max;
419                    }
420                case OpCodes.Min:
421                    {
422                        int n = (int)Evaluate(dataset, ref row, state);
423                        double min = Double.NegativeInfinity;
424                        int i = Math.Min(n, row);
425                        while (i >= 0)
426                        {
427                            int position = row - i;
428                            string variableName = dataset.GetValue(position, 1);
429                            double intValue = Convert.ToDouble(variableName);
430                            if (intValue < min) min = intValue;
431                            i--;
432                        }
433                          return min;
434                    }
435                case OpCodes.Lag:
436                    {
437                        int n = (int) Evaluate(dataset, ref row, state);
438                        if (n>row) return 0;
439                        int position = row - n;
440                        string variableName = dataset.GetValue(position, 1);
441                        double intValue = Convert.ToDouble(variableName);
442                        return intValue;
443                    }
444                case OpCodes.RSI:
445                    {
446                        /*
447                        double numberOfDays = Evaluate(dataset, ref row, state);
448                        double todayRSI=0.0;
449                        if (numberOfDays > row) return 0.0;
450                        else
451                        {
452                            double addUp = 0;
453                            double addDown = 0;
454                            double change=0;
455                            if (row == (numberOfDays))
456                            {
457                                for (int k = 1; k < (numberOfDays+1); k++)
458                                {
459                                    string variableName = dataset.GetValue(k, 1);
460                                    double intValue = Convert.ToDouble(variableName);
461                                    variableName = dataset.GetValue((k - 1), 1);
462                                    double intValue2 = Convert.ToDouble(variableName);
463                                     change = intValue - intValue2;
464                                    if (change > 0) addUp = addUp + change;
465                                    else addDown = addDown - change;
466                                 
467                                }
468                                meanUp = addUp / numberOfDays;
469                                meanDown = addDown / numberOfDays;
470                                if (meanDown != 0) todayRSI = 100 - (100 / (1 + (meanUp / meanDown)));
471                                else todayRSI = 100;
472                             }
473                            else
474                            {
475                                string variableName = dataset.GetValue(row, 1);
476                                double intValue = Convert.ToDouble(variableName);
477                                variableName = dataset.GetValue((row - 1), 1);
478                                double intValue2 = Convert.ToDouble(variableName);
479                                change = intValue - intValue2;
480
481                                addUp = meanUp * (numberOfDays - 1);
482                                addDown = meanDown * (numberOfDays - 1);
483                                if (change > 0) addUp = addUp + change;
484                                else addDown = addDown - change;
485                                meanUp = addUp / numberOfDays;
486                                meanDown = addDown / numberOfDays;
487                                if (meanDown != 0) todayRSI = 100 - (100 / (1 + (meanUp / meanDown)));
488                                else todayRSI = 100;
489                            }
490                        }
491                        if ((lastRSI < 70) && (todayRSI >= 70)) inOut = 1;
492                        else if((lastRSI > 30) && (todayRSI <= 30)) inOut=-1;
493                        lastRSI = todayRSI;*/
494                        return 0.0;
495                       
496                    }
497               
498                default: throw new NotSupportedException();
499            }
500        }
501
502        private byte MapSymbolToOpCode(ISymbolicExpressionTreeNode treeNode)
503        {
504            if (symbolToOpcode.ContainsKey(treeNode.Symbol.GetType()))
505                return symbolToOpcode[treeNode.Symbol.GetType()];
506            else
507                throw new NotSupportedException("Symbol: " + treeNode.Symbol);
508        }
509
510        // skips a whole branch
511        private void SkipInstructions(InterpreterState state)
512        {
513            int i = 1;
514            while (i > 0)
515            {
516                i += state.NextInstruction().nArguments;
517                i--;
518            }
519        }
520        [StorableConstructor]
521        private Interpreter(bool deserializing) : base(deserializing) { }
522        private Interpreter(Interpreter original, Cloner cloner) : base(original, cloner) { }
523        public override IDeepCloneable Clone(Cloner cloner)
524        {
525            return new Interpreter(this, cloner);
526        }
527
528        public Interpreter()
529            : base("SymbolicDataAnalysisExpressionTreeInterpreter", "Interpreter for symbolic expression trees including automatically defined functions.")
530        {
531            Parameters.Add(new ValueParameter<BoolValue>(CheckExpressionsWithIntervalArithmeticParameterName, "Switch that determines if the interpreter checks the validity of expressions with interval arithmetic before evaluating the expression.", new BoolValue(false)));
532            Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
533        }
534
535        [StorableHook(HookType.AfterDeserialization)]
536        private void AfterDeserialization()
537        {
538            if (!Parameters.ContainsKey(EvaluatedSolutionsParameterName))
539                Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
540        }
541       
542        //Take the symbolic expression values of the tree
543        public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows)
544        {
545            if (CheckExpressionsWithIntervalArithmetic.Value)
546                throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
547            EvaluatedSolutions.Value++; // increment the evaluated solutions counter
548            var compiler = new SymbolicExpressionTreeCompiler();
549            Instruction[] code = compiler.Compile(tree, MapSymbolToOpCode);//Take the type of symbol
550            int necessaryArgStackSize = 0;
551            for (int i = 0; i < code.Length; i++)
552            {
553                Instruction instr = code[i];
554                if (instr.opCode == OpCodes.Variable)
555                {
556                    var variableTreeNode = instr.dynamicNode as VariableTreeNode;
557                    instr.iArg0 = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
558                    code[i] = instr;
559                }
560                else if (instr.opCode == OpCodes.EMA)
561                {
562                    instr.iArg0 = EMAValue;
563                }
564            }
565            var state = new InterpreterState(code, necessaryArgStackSize);
566            //Evaluate each row of the datase
567            foreach (var rowEnum in rows)
568            {
569                int row = rowEnum;
570                state.Reset();
571                yield return Evaluate(dataset, ref row, state);
572            }
573        }
574
575    }
576}
Note: See TracBrowser for help on using the repository browser.