/// <summary>
 /// Create a trading rule from AST to the model
 /// </summary>
 /// <param name="tradingStrategyAstNode"></param>
 /// <param name="tradingStrategyModel"></param>
 private void AddTradingRuleToModel(TradingStrategyAstNode tradingStrategyAstNode, TradingStrategy tradingStrategyModel)
 {
     foreach (var tradingRuleAst in tradingStrategyAstNode.TradingRules)
     {
         if (tradingRuleAst is ConditionalRuleAstNode)
         {
             var stopLossAstRule = tradingRuleAst as ConditionalRuleAstNode;
             tradingStrategyModel.TradingRules.Add(new StopLossRule(
                 stopLossAstRule.Name,
                 ConvertExecutionFrequency(stopLossAstRule.ExecuteFrequency),
                 new Variable("position"),
                 ConvertStatementAst(stopLossAstRule.Statements),
                 (BooleanExpression)ConvertExpressionAst(stopLossAstRule.Condition),
                 CreateVariable(stopLossAstRule.PositionSet.PositionSetName)));
         }
         else if (tradingRuleAst is GeneralRuleAstNode)
         {
             tradingStrategyModel.TradingRules.Add(new TradingRule(
                 tradingRuleAst.Name,
                 ConvertExecutionFrequency(tradingRuleAst.ExecuteFrequency),
                 ConvertStatementAst(tradingRuleAst.Statements))
                 );
         }
        
     }
 }
        /// <summary>
        /// The method for executing the trading strategy.
        /// The result are the position records that located in the position sets
        /// </summary>
        /// <param name="tradingStrategy">the trading strategy</param>
        /// <param name="startDate">start date of back-testing</param>
        /// <param name="endDate">end date of back-testing</param>
        public void Execute(TradingStrategy tradingStrategy, DateTime startDate, DateTime endDate)
        {
            Currency baseCurrency = _currencyTable[tradingStrategy.Portfolio.HomeCurrency];

            // initialize evaluation context
            var collectionDataContainer = new PredefinedDataContainer();
            collectionDataContainer.Add(new Top3Currencies(_currencyDataSource, baseCurrency)); // predefined data set "Top3Currencies"
            collectionDataContainer.Add(new Bottom3Currencies(_currencyDataSource, baseCurrency)); // predefine data set "Bottom3Currencies"
            _evaluationContext = new Context(_currencyDataSource, collectionDataContainer, new ValuesTable(10), startDate);

            // Add the current date of execution into values table
            _evaluationContext.ValuesTable.Add(TODAY_STR, startDate);

            // Add base currency as a variable
            _evaluationContext.ValuesTable.Add(BASE_CURRENCY_STR, baseCurrency.Name);

            // put all the paramter definitions into the table
            foreach (var param in tradingStrategy.ConstantVariableDefinitions)
            {
                _evaluationContext.ValuesTable.Add(param.Variable.Name, param.Constant.Eval(_evaluationContext));
            }

            // initialize position set
            foreach (var positionDef in tradingStrategy.Portfolio.PositionSets)
            {
                PositionType type = (positionDef.PositionType == FXStrategy.MetaModel.PositionType.Long)?PositionType.Long:PositionType.Short;
                CreatePositionSet(positionDef.Name, baseCurrency, (int)positionDef.Number.Eval(_evaluationContext), type);
            }

            // initialize execute frequency
            tradingStrategy.TradingRules.ForEach(t => t.ExecuteFrequency.Initialize(startDate, endDate,_evaluationContext));

            // add predefined data set into collection data container
            for(DateTime currentDate = startDate; currentDate <= endDate; currentDate = currentDate.AddDays(1))
            {
                // No activities on weekend
                if (DateTimeHelper.IsWeekEnd(currentDate))
                    continue;

                _evaluationContext.ValuesTable[TODAY_STR] = currentDate;
                _evaluationContext.CurrentDate = currentDate;
                foreach (TradingRule rule in tradingStrategy.TradingRules)
                {
                    // evaluate the rule inner statement
                    // only if current date fit to its execution frequency
                    if (rule.ExecuteFrequency.CanExecute(currentDate))
                        EvaluateStatement(rule.InnerStatement);
                }
            }

        }
 /// <summary>
 /// Handles global identifier
 /// </summary>
 /// <param name="tradingStrategyAstNode"></param>
 /// <param name="tradingStrategyModel"></param>
 private void AddGlobalIdentifierToModel(TradingStrategyAstNode tradingStrategyAstNode, TradingStrategy tradingStrategyModel)
 {
     foreach (var globalVariable in tradingStrategyAstNode.GlobalIdentifierDef)
     {
         var exprAst = globalVariable.ExpressionAstNode;
         tradingStrategyModel.ConstantVariableDefinitions.Add(
             new GlobalIdentifier()
             {
                 Variable = CreateVariable(globalVariable.VariableName, exprAst.GetType()),
                 Constant = ConvertExpressionAst(exprAst)
             }
             );
     }
 }
        /// <summary>
        /// Start transform an abstract syntax tree into the model
        /// </summary>
        /// <param name="tradingStrategyAstNode">the node on abstract syntax represents trading strategy</param>
        /// <returns>model of a trading strategy</returns>
        public TradingStrategy Transform(TradingStrategyAstNode tradingStrategyAstNode)
        {
            if (tradingStrategyAstNode == null)
                throw new ArgumentException("tradingStrategyAstNode cannot be null.");

            TradingStrategy tradingStrategyModel = new TradingStrategy();

            AddGlobalIdentifierToModel(tradingStrategyAstNode, tradingStrategyModel);

            AddPositionSetDefToModel(tradingStrategyAstNode, tradingStrategyModel);

            AddPortfolioParamToModel(tradingStrategyAstNode, tradingStrategyModel);

            AddTradingRuleToModel(tradingStrategyAstNode, tradingStrategyModel);

            return tradingStrategyModel;
        }
        private static TradingStrategy ConstructTradingStrategy()
        {
            TradingStrategy tradingStrategy = new TradingStrategy()
            {
                ConstantVariableDefinitions = new System.Collections.Generic.List<GlobalIdentifier>(){
                     new GlobalIdentifier(){ 
                         Variable = new Variable("reEntryExRatePercent", typeof(int)),
                         Constant = new Constant(typeof(decimal),0.05)},
                    new GlobalIdentifier(){ 
                         Variable = new Variable("noOfLongPosition",typeof(int)),
                         Constant = new Constant(typeof(int),3)},
                    new GlobalIdentifier(){ 
                         Variable = new Variable("noOfShortPosition",typeof(int)),
                         Constant = new Constant(typeof(int),3)}
                 },
                Portfolio = new Portfolio()
                {
                    HomeCurrency = "EUR",
                    PositionSets = new List<PositionSet>()
                    {
                        new PositionSet(){
                             Name = "LongPositions", Number = new Variable("noOfLongPosition",typeof(int)), PositionType = FXStrategy.MetaModel.PositionType.Long
                        },
                        new PositionSet(){
                            Name = "ShortPositions", Number = new Variable("noOfShortPosition", typeof(int)), PositionType = FXStrategy.MetaModel.PositionType.Short
                        }
                    }
                },

                TradingRules = new System.Collections.Generic.List<TradingRule>()
                {
                    //new StopLossRule(
                    //    "Stop loss rule",
                    //    new PeriodicTimeDefinition(1, PeriodicType.Day),
                    //    new Variable("position",typeof(Position)),
                    //    new CompositeStatement(
                    //        new List<Statement>{
                    //           new Assignment(new Variable("exRateOverTime",typeof(TimeSeriesData)),
                    //               new PropertyAccessor(
                    //                   new ArgumentedVariable("CurrencyPairSet", typeof(CurrencyPair),
                    //                       new Expression[]{ new Constant(typeof(string), "EUR"), 
                    //                        new PropertyAccessor( new Variable("position"),"Currency")
                    //                       }),
                    //                   "ExchangeRates")
                    //                   ),
                    //            new Assignment(new Variable("currentExRate"),
                    //                new MethodAccessor(new Variable("exRateOverTime",typeof(TimeSeriesData)),
                    //                    "At", new Expression[]{new Variable("TODAY")})),
                    //            new Assignment(new Variable("movingAVG"),
                    //                new MethodAccessor(new Variable("exRateOverTime",typeof(TimeSeriesData)),
                    //                    "MovingAvg", new Expression[]{new Variable("TODAY"),new Constant(typeof(int),14)}))
                    //        }
                    //        ),
                    //    new LessThan{
                    //         LeftExpression = new Variable("currentExRate"),
                    //         RightExpression = new Variable("movingAVG")
                    //    },
                    //    new Variable("LongPositions",typeof(PositionSet))
                    //    ),


                    //new TradingRule(
                    //    "Close Position after a term",
                    //    new PeriodicTimeDefinition( 3,
                    //         PeriodicType.Month
                    //    ),
                    //        new ForAllStatement(
                    //            new Variable( "position",typeof(string)),
                    //             new Variable("LongPositions",typeof(PositionSet)),
                                 
                    //                new ClosePosition(
                    //                  new Variable("position",typeof(Position))
                    //                )
                                
                    //        )
                        
                    //    ),
                    new TradingRule(
                        "reallocation",
                         new WeekDayTimeDefinition(){
                              DayOfWeek = DayOfWeek.Friday
                         },
                         new CompositeStatement(new System.Collections.Generic.List<Statement>(){

                             new ForAllStatement(
                                  new Variable("position",typeof(Position)),
                                 new Variable("LongPositions",typeof(PositionSet)),
                                 
                                new IfStatement(
                                    new IsNotInSet(){
                                        LeftExpression = new PropertyAccessor(
                                            new Variable("position",typeof(Position)),
                                            "Currency")
                                        , RightExpression = new Variable("Top3Currencies",typeof(PredefinedDataSet))
                                          
                                    },
                                    new ClosePosition(new Variable("position",typeof(Position)))
                                )
                             ),
                             new ForAllStatement(
                                  new Variable("currency", typeof(string)),
                                 new Variable("Top3Currencies",typeof(PredefinedDataSet)),
                                  new IfStatement(
                                          new IsNotInSet(){
                                               LeftExpression = new Variable("currency",typeof(string)), 
                                               RightExpression = new CollectionPropertiesAccessor(
                                                  new Variable("LongPositions",typeof(PositionSet)),
                                                   "Currency"
                                               )
                                          },
                                        new OpenPosition(
                                            new Variable("LongPositions", typeof(PositionSet)),
                                            new Variable("currency",typeof(string))
                                        )
                                     )
                                 
                             ),

                               new ForAllStatement(
                                   new Variable("position",typeof(Position)),
                                 new Variable("ShortPositions",typeof(PositionSet)),
                                new IfStatement(
                                    new IsNotInSet(){
                                        LeftExpression = new PropertyAccessor(new Variable("position",typeof(Position)), "Currency")
                                        , RightExpression = new Variable("Bottom3Currencies",typeof(PredefinedDataSet))
                                               
                                    },
                                    new ClosePosition(new Variable("position",typeof(Position)))
                                )
                            )
                             ,
                             new ForAllStatement(
                                 new Variable( "currency",typeof(string)),
                                  new Variable("Bottom3Currencies",typeof(PredefinedDataSet)),
                                  
                                new IfStatement(
                                    new IsNotInSet(){
                                        LeftExpression = new Variable("currency",typeof(Position)), 
                                            RightExpression = new CollectionPropertiesAccessor(
                                            new Variable("ShortPositions",typeof(PositionSet)),
                                            "Currency"
                                        )
                                    },
                                    new OpenPosition(
                                        new Variable("ShortPositions",typeof(PositionSet)),
                                        new Variable("currency",typeof(string))
                                    )
                                )
                                 
                             )
                         }
                ))
                }
            };
            return tradingStrategy;
        }
        public void ExchangeRateAccessorTest()
        {

            TradingStrategy tradingStrategy = new TradingStrategy()
            {
                ConstantVariableDefinitions = new System.Collections.Generic.List<GlobalIdentifier>(){
                     new GlobalIdentifier(){ 
                         Variable = new Variable("reEntryExRatePercent", typeof(int)),
                         Constant = new Constant(typeof(decimal),0.05)},
                    new GlobalIdentifier(){ 
                         Variable = new Variable("noOfLongPosition",typeof(int)),
                         Constant = new Constant(typeof(int),3)},
                    new GlobalIdentifier(){ 
                         Variable = new Variable("noOfShortPosition",typeof(int)),
                         Constant = new Constant(typeof(int),3)}
                 },
                Portfolio = new Portfolio()
                {
                    HomeCurrency = "EUR",
                    PositionSets = new List<PositionSet>()
                    {
                        new PositionSet(){
                             Name = "LongPositions", Number = new Variable("noOfLongPosition",typeof(int)), PositionType = FXStrategy.MetaModel.PositionType.Long
                        },
                        new PositionSet(){
                            Name = "ShortPositions", Number = new Variable("noOfShortPosition", typeof(int)), PositionType = FXStrategy.MetaModel.PositionType.Short
                        }
                    }
                },

                TradingRules = new System.Collections.Generic.List<TradingRule>()
                {
                    new TradingRule("test", new ConcreteTimeDefinition(){
                         ExecuteTime = new DateTime(2006,1,30)
                    },
                     new Assignment(
                        new Variable("exRateMVG", typeof(decimal)),
                        new AtTime(
                        new ExchangeRateAccessor(
                            new Constant(typeof(string), "EUR"),
                            new Constant(typeof(string), "USD"))
                            ,
                            new Constant(typeof(DateTime), new DateTime(2006,1,30)))))
                }
            };

            FXEntities.FXEntities fxEntities = new FXEntities.FXEntities();
             CurrencyDataSource currencyDataSource = new CurrencyDataSource(fxEntities);
            StrategyInterpreter target = new StrategyInterpreter(fxEntities, currencyDataSource);
             DateTime startDate = new DateTime(2006, 1, 29);
            DateTime endDate = new DateTime(2006, 1, 31);
            target.Execute(tradingStrategy, startDate, endDate);


        }
        /// <summary>
        /// Handles parameters in the trading strategy AST node
        /// </summary>
        /// <param name="tradingStrategyAstNode"></param>
        /// <param name="tradingStrategyModel"></param>
        private void AddPortfolioParamToModel(TradingStrategyAstNode tradingStrategyAstNode, TradingStrategy tradingStrategyModel)
        {

            foreach (var parameter in tradingStrategyAstNode.StrategyParameters)
            {
                Type type = null;
                object value = null;
                string parameterName = null;

                if (parameter.Value is StringAstNode)
                {
                    var strAst = parameter.Value as StringAstNode;
                    type = typeof(string);
                    value = strAst.Value;
                    parameterName = parameter.Name;
                }

                if (parameterName != null)
                {
                    if (parameterName.ToLower() == "homecurrency")
                        tradingStrategyModel.Portfolio.HomeCurrency = (string)value;
                    else
                    {
                        throw new Exception("Unknown strategy parameter: " + parameterName);
                    }
                }
            }
        }
 /// <summary>
 /// Handles transformation of position set
 /// </summary>
 /// <param name="tradingStrategyAstNode"></param>
 /// <param name="tradingStrategyModel"></param>
 private void AddPositionSetDefToModel(TradingStrategyAstNode tradingStrategyAstNode, TradingStrategy tradingStrategyModel)
 {
     foreach (var positionSetDef in tradingStrategyAstNode.PositionSets)
     {
         CreateVariable(positionSetDef.Name, typeof(PositionSet));
         tradingStrategyModel.Portfolio.PositionSets.Add(new PositionSet()
         {
             Name = positionSetDef.Name,
          Number = ConvertExpressionAst(positionSetDef.Number),
             PositionType = ConvertPositionTypeAst(positionSetDef.PositionType)
         });
     }
 }