Free cookie consent management tool by TermsFeed Policy Generator

source: branches/sluengo/Interpreter.cs @ 9137

Last change on this file since 9137 was 9136, checked in by sluengo, 11 years ago
File size: 25.3 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                        double timeValue = Evaluate(dataset, ref row, state);
375                        if (EMAValue == null || EMAValue.GetLength(0) < dataset.Rows)
376                            EMAValue = dataset.GetDoubleValues("Close").ToArray();
377                        int lastRow = row - 1;
378                        EMAValue[row] = double.NaN;
379                        if (row == (timeValue - 1))
380                        {
381                            string variableName = dataset.GetValue(row, 2);
382                            double meanValue = Convert.ToDouble(variableName);
383                            EMAValue[row] = meanValue / timeValue;
384                        }
385                        if (row > (timeValue - 1))
386                        {
387                            lastValue = ((IList<double>)currentInstr.iArg0)[row];
388                            string variableName = dataset.GetValue(row, 1);
389                            double meanValue = Convert.ToDouble(variableName);
390                            double factor = 2 / (timeValue + 1);
391                            EMAValue[row] = (meanValue * factor) + (EMAValue[lastRow] * (1 - factor));
392                        }
393                        return EMAValue[row];
394
395
396                    }
397                case OpCodes.Constant:
398                    {
399                        var constTreeNode = currentInstr.dynamicNode as ConstantTreeNode;
400                        return constTreeNode.Value;
401                    }
402                case OpCodes.BoolConstant:
403                    {
404                        var boolConstTreeNode = currentInstr.dynamicNode as BoolConstantTreeNode;
405                        return boolConstTreeNode.Value;
406                    }
407                case OpCodes.ConstantInt:
408                    {
409                        var constIntTreeNode = currentInstr.dynamicNode as ConstantIntTreeNode;
410                        return constIntTreeNode.Value;
411                    }
412                case OpCodes.Max:
413                    {
414                        int n = (int) Evaluate(dataset, ref row, state);
415                        double max = Double.NegativeInfinity;
416                        int i = Math.Min(n,row);
417                        while(i>=0)
418                        {
419                            int position = row - i;
420                            string variableName = dataset.GetValue(position, 1);
421                            double intValue = Convert.ToDouble(variableName);
422                            if (intValue>max) max = intValue;
423                        i--;
424                        }
425                        return max;
426                    }
427                case OpCodes.Min:
428                    {
429                        int n = (int)Evaluate(dataset, ref row, state);
430                        double min = Double.NegativeInfinity;
431                        int i = Math.Min(n, row);
432                        while (i >= 0)
433                        {
434                            int position = row - i;
435                            string variableName = dataset.GetValue(position, 1);
436                            double intValue = Convert.ToDouble(variableName);
437                            if (intValue < min) min = intValue;
438                            i--;
439                        }
440                          return min;
441                    }
442                case OpCodes.Lag:
443                    {
444                        int n = (int) Evaluate(dataset, ref row, state);
445                        if (n>row) return 0;
446                        int position = row - n;
447                        string variableName = dataset.GetValue(position, 1);
448                        double intValue = Convert.ToDouble(variableName);
449                        return intValue;
450                    }
451                case OpCodes.RSI:
452                    {
453                        /*
454                        double numberOfDays = Evaluate(dataset, ref row, state);
455                        double todayRSI=0.0;
456                        if (numberOfDays > row) return 0.0;
457                        else
458                        {
459                            double addUp = 0;
460                            double addDown = 0;
461                            double change=0;
462                            if (row == (numberOfDays))
463                            {
464                                for (int k = 1; k < (numberOfDays+1); k++)
465                                {
466                                    string variableName = dataset.GetValue(k, 1);
467                                    double intValue = Convert.ToDouble(variableName);
468                                    variableName = dataset.GetValue((k - 1), 1);
469                                    double intValue2 = Convert.ToDouble(variableName);
470                                     change = intValue - intValue2;
471                                    if (change > 0) addUp = addUp + change;
472                                    else addDown = addDown - change;
473                                 
474                                }
475                                meanUp = addUp / numberOfDays;
476                                meanDown = addDown / numberOfDays;
477                                if (meanDown != 0) todayRSI = 100 - (100 / (1 + (meanUp / meanDown)));
478                                else todayRSI = 100;
479                             }
480                            else
481                            {
482                                string variableName = dataset.GetValue(row, 1);
483                                double intValue = Convert.ToDouble(variableName);
484                                variableName = dataset.GetValue((row - 1), 1);
485                                double intValue2 = Convert.ToDouble(variableName);
486                                change = intValue - intValue2;
487
488                                addUp = meanUp * (numberOfDays - 1);
489                                addDown = meanDown * (numberOfDays - 1);
490                                if (change > 0) addUp = addUp + change;
491                                else addDown = addDown - change;
492                                meanUp = addUp / numberOfDays;
493                                meanDown = addDown / numberOfDays;
494                                if (meanDown != 0) todayRSI = 100 - (100 / (1 + (meanUp / meanDown)));
495                                else todayRSI = 100;
496                            }
497                        }
498                        if ((lastRSI < 70) && (todayRSI >= 70)) inOut = 1;
499                        else if((lastRSI > 30) && (todayRSI <= 30)) inOut=-1;
500                        lastRSI = todayRSI;*/
501                        return 0.0;
502                       
503                    }
504               
505                default: throw new NotSupportedException();
506            }
507        }
508
509        private byte MapSymbolToOpCode(ISymbolicExpressionTreeNode treeNode)
510        {
511            if (symbolToOpcode.ContainsKey(treeNode.Symbol.GetType()))
512                return symbolToOpcode[treeNode.Symbol.GetType()];
513            else
514                throw new NotSupportedException("Symbol: " + treeNode.Symbol);
515        }
516
517        // skips a whole branch
518        private void SkipInstructions(InterpreterState state)
519        {
520            int i = 1;
521            while (i > 0)
522            {
523                i += state.NextInstruction().nArguments;
524                i--;
525            }
526        }
527        [StorableConstructor]
528        private Interpreter(bool deserializing) : base(deserializing) { }
529        private Interpreter(Interpreter original, Cloner cloner) : base(original, cloner) { }
530        public override IDeepCloneable Clone(Cloner cloner)
531        {
532            return new Interpreter(this, cloner);
533        }
534
535        public Interpreter()
536            : base("SymbolicDataAnalysisExpressionTreeInterpreter", "Interpreter for symbolic expression trees including automatically defined functions.")
537        {
538            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)));
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        [StorableHook(HookType.AfterDeserialization)]
543        private void AfterDeserialization()
544        {
545            if (!Parameters.ContainsKey(EvaluatedSolutionsParameterName))
546                Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
547        }
548       
549        //Take the symbolic expression values of the tree
550        public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows)
551        {
552            if (CheckExpressionsWithIntervalArithmetic.Value)
553                throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
554            EvaluatedSolutions.Value++; // increment the evaluated solutions counter
555            var compiler = new SymbolicExpressionTreeCompiler();
556            Instruction[] code = compiler.Compile(tree, MapSymbolToOpCode);//Take the type of symbol
557            int necessaryArgStackSize = 0;
558            for (int i = 0; i < code.Length; i++)
559            {
560                Instruction instr = code[i];
561                if (instr.opCode == OpCodes.Variable)
562                {
563                    var variableTreeNode = instr.dynamicNode as VariableTreeNode;
564                    instr.iArg0 = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
565                    code[i] = instr;
566                }
567                else if (instr.opCode == OpCodes.EMA)
568                {
569                    instr.iArg0 = EMAValue;
570                }
571            }
572            var state = new InterpreterState(code, necessaryArgStackSize);
573            //Evaluate each row of the datase
574            foreach (var rowEnum in rows)
575            {
576                int row = rowEnum;
577                state.Reset();
578                yield return Evaluate(dataset, ref row, state);
579            }
580        }
581
582    }
583}
Note: See TracBrowser for help on using the repository browser.