Exemple #1
0
        /*****************************************************************************
        *  FUNCTION:       RunAnalysis
        *  Description:
        *  Parameters:     None
        *****************************************************************************/
        public AnalysisResult RunAnalysis()
        {
            int    i;
            bool   buy, sell;
            string str_expression, str_evaluated_rule;
            double gain_loss = 0.0, cash = inPrincipalAmt, investments = 0.0, transaction_amt = 0.0;
            int    units = 0, units_held = 0, total_transactions = 0;

            String[]       buy_conditions = inBuyRule.Split(RuleParserInputs.Operators, StringSplitOptions.RemoveEmptyEntries);
            String[]       sell_conditions = inSellRule.Split(RuleParserInputs.Operators, StringSplitOptions.RemoveEmptyEntries);
            AnalysisResult analysis_result = new AnalysisResult();

            PercentComplete = 0.0;

            //Get the list of functions passed in the current Buy and Sell rules
            //(so that we don't have to itterate again for each data point)
            current_buy_functions.Clear();
            current_sell_functions.Clear();
            foreach (Fn func in RuleParserInputs.Fns)
            {
                foreach (String buy_cond in buy_conditions)
                {
                    if (buy_cond.Contains(StringEnum.GetStringValue(func)))
                    {
                        current_buy_functions.Add(func);
                    }
                }
                foreach (String sell_cond in sell_conditions)
                {
                    if (sell_cond.Contains(StringEnum.GetStringValue(func)))
                    {
                        current_sell_functions.Add(func);
                    }
                }
            }

            //ex. ((MACD_DIFF > 0) AND (P < AVG[P][-5..0]))

            //For every day in data
            for (i = 0; i < inEquity.HistoricalPriceDate.Count; i++)
            {
                //Initialize analysis result values
                analysis_result.cash_totals.Add(0.0);
                analysis_result.investments_totals.Add(0.0);
                analysis_result.net_change_daily.Add(0.0);
                analysis_result.units_change_daily.Add(0);

                //Evaluate the given historical data point against each of the buy rules
                buy = false;
                str_evaluated_rule = inBuyRule;

                //Get the number of units to buy
                units = GetNumberOfUnits(str_evaluated_rule, out str_evaluated_rule, inEquity.HistoricalPrice[i], cash);

                //Parse each of the individual conditional expressions and evaluate the overall rule
                foreach (String buy_cond in buy_conditions)
                {
                    str_expression     = Parse(buy_cond, inEquity, i, current_buy_functions);
                    str_evaluated_rule = str_evaluated_rule.Replace(buy_cond, str_expression);
                }
                buy = Evaluate(str_evaluated_rule);

                //Update holdings if the buy rule evaluates to True
                if (buy)
                {
                    transaction_amt = inEquity.HistoricalPrice[i] * units;
                    if (cash >= (transaction_amt))
                    {
                        units_held += units;
                        cash       -= transaction_amt;
                        investments = (inEquity.HistoricalPrice[i] * units_held);
                        total_transactions++;
                    }
                }

                //Evaluate the given historical data point against each of the sell rules
                sell = false;
                str_evaluated_rule = inSellRule;

                //Get the number of units to sell
                units = GetNumberOfUnits(str_evaluated_rule, out str_evaluated_rule, 1.0, investments);

                foreach (String sell_cond in sell_conditions)
                {
                    str_expression     = Parse(sell_cond, inEquity, i, current_sell_functions);
                    str_evaluated_rule = str_evaluated_rule.Replace(sell_cond, str_expression);
                }
                sell = Evaluate(str_evaluated_rule);

                if (sell)
                {
                    transaction_amt = inEquity.HistoricalPrice[i] * units;
                    if (investments >= transaction_amt)
                    {
                        units_held -= units;
                        cash       += transaction_amt;
                        investments = (inEquity.HistoricalPrice[i] * units_held);
                        total_transactions++;
                        units = 0;
                    }
                }

                //update Analyis result structure
                analysis_result.cash_totals[i]        = cash;
                analysis_result.investments_totals[i] = investments;
                analysis_result.net_change_daily[i]   = (cash + investments);
                analysis_result.units_change_daily[i] = units_held;
                analysis_result.dates_from_to         = new Tuple <DateTime, DateTime>(inEquity.HistoricalPriceDate[0],
                                                                                       inEquity.HistoricalPriceDate[inEquity.HistoricalPriceDate.Count - 1]);

                if (i > 0)
                {
                    analysis_result.net_change_daily[i] -= (analysis_result.cash_totals[i - 1] +
                                                            analysis_result.investments_totals[i - 1]);

                    analysis_result.units_change_daily[i] -= analysis_result.units_change_daily[i - 1];
                }


                //Update progress
                PercentComplete = ((double)(i + 1) / (double)inEquity.HistoricalPriceDate.Count);
            }

            PercentComplete = 1.0;

            gain_loss = (cash + investments) - inPrincipalAmt;
            analysis_result.net_change = gain_loss;

            return(analysis_result);
        }
        private int ExpressionEndIndex(string pRuleString, int pFromIndex)
        {
            int    nesting_level = 0, param_level = 0;
            int    index1  = 0;
            string tempStr = "";
            bool   isfound = false;

            //find the end of the expression
            nesting_level = 0;
            param_level   = 0;
            isfound       = false;
            index1        = pFromIndex;

            while (index1 < pRuleString.Length)
            {
                switch (pRuleString[index1])
                {
                case '(':
                    nesting_level++;
                    break;

                case ')':
                    nesting_level--;
                    break;

                case '[':
                    param_level++;
                    break;

                case ']':
                    param_level--;
                    break;

                default:
                    break;
                }
                tempStr = pRuleString.SubWord(index1);

                try
                {
                    double.Parse(tempStr);
                    isfound = true;
                    index1 += tempStr.Length;
                }
                catch
                {
                    if (RuleParserInputs.Fns.Where(a => StringEnum.GetStringValue(a) == tempStr).Count() > 0)
                    {
                        isfound = true;
                        index1 += tempStr.Length - 1;
                    }
                    else if (RuleParserInputs.VarList.Where(a => StringEnum.GetStringValue(a) == tempStr).Count() > 0 &&
                             (param_level == 0))
                    {
                        isfound = true;
                        index1 += tempStr.Length - 1;
                    }
                }

                if (isfound && (param_level == 0) && (nesting_level == 0))
                {
                    //look ahead to the next character in case a valid fn or param string is found
                    // to ensure the whole parameter is taken
                    if (index1 < (pRuleString.Length - 1) && pRuleString[index1 + 1] == '[')
                    {
                        param_level++;
                    }
                    else
                    {
                        break;
                    }
                }

                index1++;
            }

            return(index1);
        }
        /*****************************************************************************
        *  FUNCTION:       Parse
        *  Description:    Replaces a primitive expression with corresponding numeric values
        *                  to enable evaluation.
        *
        *                  Ex. (P < AVG[P][-5..0])
        *  Parameters:
        *
        *****************************************************************************/
        private String Parse(String pExpression, Equity pEqIn, int pIndex, List <Fn> pFNs)
        {
            string parameter, str_expression, fn_str;
            double parameter_value = 0.0;

            string[] split_str;
            int      index1, index2;
            Variable in_param;

            str_expression = pExpression;
            //For each function in the expression being parsed
            foreach (Fn func in pFNs)
            {
                fn_str = "";
                if (pExpression.Contains(StringEnum.GetStringValue(func)))
                {
                    //Get the substring containing only the logical expression for this function
                    index1 = pExpression.IndexOf(StringEnum.GetStringValue(func));
                    index2 = pExpression.IndexOf("]", index1);

                    if (pExpression.Length > index2 && pExpression.ToCharArray()[index2 + 1] == '[')
                    {
                        index2 = pExpression.IndexOf("]", index2 + 1);
                    }

                    fn_str = pExpression.Substring(index1, index2 - index1 + 1);

                    try
                    {
                        //Evaluate the function and replace the substring in the original parent expression with the value
                        str_expression = str_expression.Replace(fn_str.Trim(), GetFunction(func, pEqIn, fn_str, pIndex).ToString());
                    }
                    catch (IndexOutOfRangeException)
                    {
                        //The index will be out of range even for a valid command if the function operates on past data that
                        // isn't available at the start of a series.
                        //
                        // Ex. AVG[P][-5..0] --> at the start of the price data series, there aren't 5 previous data points available
                        //     to calculate an average on.
                        //
                        // In this case, just return false to allow the rest of the command to be processed.
                        return("false");
                    }
                    catch (Exception)
                    {
                        errorIndex[0] = index1;
                        errorIndex[1] = index2;
                        return("ERROR");
                    }
                }
            }

            split_str = str_expression.Split(RuleParserInputs.Comparators, StringSplitOptions.RemoveEmptyEntries);

            foreach (string exp_part in split_str)
            {
                parameter = CleanExpression(exp_part.Trim()).Replace("NOT", "");

                if (Helpers.ValidateNumeric(parameter) == false)
                {
                    in_param = GetParameterType(parameter);

                    try
                    {
                        //If the data to be analyzed is one of the MACD signals, ensure the passed index is valid
                        if (in_param == Variable.MACD_DIFF || in_param == Variable.MACD_SIG)
                        {
                            if (pIndex > (pEqIn.HistoricalPrice.Count() - pEqIn.MACD_C.Count()))
                            {
                                parameter_value = GetParameter(pEqIn, parameter, pIndex);
                                str_expression  = str_expression.ReplaceFirstOccurrence(parameter, parameter_value.ToString());
                            }
                        }
                        else
                        {
                            parameter_value = GetParameter(pEqIn, parameter, pIndex);
                            str_expression  = str_expression.ReplaceFirstOccurrence(parameter, parameter_value.ToString());
                        }
                    }
                    catch (IndexOutOfRangeException)
                    {
                        return("false");
                    }
                    catch (Exception)
                    {
                        errorIndex[0] = 0;
                        errorIndex[1] = 0;
                        return("ERROR");
                    }
                }
            }

            return(str_expression);
        }
        private String PreprocessRule(String pRuleString)
        {
            string subexpression = "", returnString = "";
            int    index1 = 0, index2 = 0;
            string indexStr = "", newRule = "";

            returnString = pRuleString;
            returnString = (new Regex("\\s+")).Replace(returnString, " ");

            //Find all instances of the "becomes" keyword and create the edge-detection string
            foreach (int index in pRuleString.AllIndexesOf("becomes"))
            {
                index1 = ExpressionStartIndex(pRuleString, index - 1);
                index2 = ExpressionEndIndex(pRuleString, index + 7);

                subexpression = pRuleString.Substring(index1, index2 - index1);

                //Replace all existing index specifiers with ones decremented by 1
                index1  = subexpression.IndexOf('[');
                newRule = subexpression;
                while (index1 >= 0)
                {
                    index2 = subexpression.IndexOf(']', index1);

                    if (index2 > index1)
                    {
                        indexStr = subexpression.Substring(index1 + 1, index2 - index1 - 1);
                    }
                    else
                    {
                        break;
                    }

                    //replace the indexStr with indexes decremented by 1
                    foreach (Match si in Regex.Matches(indexStr, "[-]*[0-9]+"))
                    {
                        indexStr = indexStr.ReplaceFirstOccurrence(si.Value, (int.Parse(si.Value) - 1).ToString());
                    }

                    newRule = newRule.ReplaceFirstOccurrence(subexpression.Substring(index1 + 1, index2 - index1 - 1), indexStr);
                    index1  = subexpression.IndexOf('[', index2);
                }

                //For variables used without an index specifier (indicating current data), need to add [-1] specifier
                foreach (Variable vari in RuleParserInputs.VarList)
                {
                    MatchCollection mc = Regex.Matches(newRule, "\\b" + StringEnum.GetStringValue(vari) + "\\b");
                    int             i = 0, offset = 0;

                    while (i < mc.Count)
                    {
                        index1 = mc[i++].Index + offset;
                        index2 = index1 + StringEnum.GetStringValue(vari).Length;
                        if (newRule[index2] != '[' && newRule[index2] != ']')
                        {
                            newRule = newRule.Insert(index2, "[-1]");
                            offset += 4;
                        }
                    }
                }

                //Create the new subexpression, replacing "becomes" with the same rule using 'previous' indexes
                newRule = "(" + subexpression.Replace("becomes", "") + " AND NOT(" + newRule.Replace("becomes", "") + "))";
                newRule = newRule.Replace("  ", " ").Trim();

                returnString = returnString.Replace(subexpression, newRule);
                returnString = (new Regex("\\s+")).Replace(returnString, " ");
            }

            return(returnString);
        }