/* Excercise all options at the end of the day */
        public static void ExcerciseGasOptions(TradeSet sourcePF)
        {
            DateTime marketDate = sourcePF.MarketDate;

            IEnumerable<Tradelet> tradelets = sourcePF._trades.Values.SelectMany(k => k.tradelets.Values)
                                    .Where(k => k.MyTrade.isOption && k.DelStart > marketDate); // > tradeDate removes many possibilities: speed improvement

            Dictionary<DateTime, DateTime> exDates;
            double price; Product prod; Trade trade; Trade exercTrade;
            int signExcerTrade = 0;

            foreach (Tradelet tlet in tradelets.ToList())
            {
                trade = tlet.MyTrade;
                prod = trade.MyProduct;
                exDates = TradingCenter.TCEachTenor(trade.OptionTenorType,  tlet.DelStart, tlet.DelEnd).Select(k =>
                                    new KeyValuePair<DateTime, DateTime>(k, prod.TC.GetGasOptExDate(trade.OptionTenorType, k, trade._instrument.isExchange))).ToDictionary(k => k.Key, k => k.Value);

                foreach (DateTime day in exDates.Keys)
                {
                    price = prod.ReturnCurveSeries().GetValue(trade.OptionTenorType, day, marketDate);
                    if (trade.OptionType == OPTION_TYPE.PUT && trade.Strike > price)
                    {
                        trade.isExcercised = true;
                        signExcerTrade = -1;
                    }
                    else if (trade.OptionType == OPTION_TYPE.CALL && trade.Strike < price)
                    {
                        trade.isExcercised = true;
                        signExcerTrade = 1;
                    }
                    else
                    {
                        trade.isExpired = true;
                    }
                    exercTrade = new Trade() {
                                        DealID = sourcePF.MyTradeCollection.CreateFakeID(), TradeDate = marketDate,
                                        Volume = signExcerTrade * trade.Volume, Price = trade.Strike,
                                        UnitName = prod.UnitName,
                                        CCY = prod.CCY,
                                        ProductName = prod.Name,
                                        MyProduct = prod,
                                        DelStart = day, DelEnd = TradingCenter.TCTenorSelector(day, trade.OptionTenorType, 1).AddDays(-1),
                                        exerciseTrade = trade, OptionID = trade.OptionID};
                    sourcePF._trades.Add(exercTrade.DealID, exercTrade);
                }
            }
        }
        /* No trade-by trade PnL, monthly hedging + DA & BoM for dailies. BoM = average price for rest of month, not a 'real BoM' price */
        public static TradeSet PerfectMonthlyHedge(TradeSet sourcePF)
        {
            /* original trades are prices, add new hedges and price them [PnL will be zero, but we need position] */
            // @@@ A) just add new trades ... slower but who cares :-)
            // add accumulate exposure and create opposite trade
            // IEnumerable<IGrouping<DateTime, Tradelet>> monthlyTradeletGroups = sourcePF._trades.Values.SelectMany(k => k.tradelets.Values).GroupBy(k => k.FirstMonth);
            TradeSet newPF = sourcePF.CloneTradeSet(); // either newPF or alternatively remove replace trades from previous ... but we clone it anyway? here we can look at single optiones as well ... hm :(
            // now : just add ONE trade into the newPF and think about everything else later

            DateTime marketDate = sourcePF.MarketDate; DateTime runDate = DateTime.MinValue;
            Trade newTrade;
            Product prod;
            CurveSeries curves;
            TradingCenter tc;
            int runTenorType;

            double deltaExpo;
            double price;

            Dictionary<DateTime, object[]> hedgeGran; // @@@ <del start: del start, del end, granularity

            foreach (string productName in sourcePF.ProductNames) // @@@ replace location with productname, don't mix stuff up
            {
                prod = DynamicData.GetProduct(productName);
                curves = prod.ReturnCurveSeries();
                tc = prod.TC;

                runTenorType = TENOR_TYPE.DAY;
                foreach (DateTime delDay in TradingCenter.TCEachDay(marketDate.AddDays(1), tc.reqNextBD(marketDate))) // here single trades and below BOM? well yes, that is the liquidity ide ... to improve and generalize
                {
                    runDate = delDay;
                    price = curves.GetValue(runTenorType, delDay, marketDate);
                    deltaExpo = sourcePF.GetExposure(EXPOSURE_TYPE.DELTA, runTenorType, productName, delDay);
                    newTrade = new Trade() {
                                        DealID = sourcePF.MyTradeCollection.CreateFakeID(), TradeDate = marketDate,
                                        Volume = prod.UnitSet.ToStandardSize(-1 * deltaExpo, 1),
                                        Price = price,
                                        UnitName = prod.UnitName,
                                        CCY = prod.CCY,
                                        ProductName = prod.Name,
                                        MyProduct = prod,
                                        DelStart = delDay, DelEnd = TradingCenter.TCTenorSelector(delDay, runTenorType, 1).AddDays(-1)};
                    newTrade.PriceTrade(marketDate);
                    newPF._trades.Add(newTrade.DealID, newTrade);
                }

                // loop till next Month >> create a single BoM trade; @@@ ultimatively, create hedge calendar <startDate, endDate, Granularity>: groups which are priced and hedged as once @@@ but finish simple version first!
                DateTime delStart = runDate.AddDays(1);
                DateTime delEnd = TradingCenter.TCTenorSelector(runDate, TENOR_TYPE.MONTH, 1).AddDays(-1);
                runDate = delEnd;
                if (delEnd >= delStart)
                {
                    List<DateTime> bomDates = TradingCenter.TCEachDay(delStart, delEnd).ToList();
                    price = bomDates.Select(k => curves.GetValue(runTenorType, k, marketDate)).Average();
                    deltaExpo = bomDates.Select(k => sourcePF.GetExposure(EXPOSURE_TYPE.DELTA, runTenorType, productName, k)).Sum();

                    newTrade = new Trade() {
                        DealID = sourcePF.MyTradeCollection.CreateFakeID(), TradeDate = marketDate,
                        Volume = prod.UnitSet.ToStandardSize(-1 * deltaExpo, 1),
                        Price = price,
                        UnitName = prod.UnitName,
                        CCY = prod.CCY,
                        ProductName = prod.Name,
                        MyProduct = prod,
                        DelStart = delStart, DelEnd = delEnd};
                    newTrade.PriceTrade(marketDate);
                    newPF._trades.Add(newTrade.DealID, newTrade);
                }

                runTenorType = TENOR_TYPE.MONTH;
                foreach (DateTime delDay in TradingCenter.TCEachTenor(runTenorType, runDate.AddDays(1), sourcePF.GetLastDelDate(productName)))
                {
                    price = curves.GetValue(runTenorType, delDay, marketDate);
                    deltaExpo = sourcePF.GetExposure(EXPOSURE_TYPE.DELTA, runTenorType, productName, delDay);
                                        newTrade = new Trade() {
                                        DealID = sourcePF.MyTradeCollection.CreateFakeID(), TradeDate = marketDate,
                                        Volume = prod.UnitSet.ToStandardSize(-1 * deltaExpo, TradingCenter.TCTenorSelector(delDay, runTenorType, 1).AddDays(-1).Day),
                                        Price = price, UnitName = prod.UnitName, CCY = prod.CCY, ProductName = prod.Name, MyProduct = prod,
                                        DelStart = delDay, DelEnd = TradingCenter.TCTenorSelector(delDay, runTenorType, 1).AddDays(-1)};
                    //@@@ add default portfolio? hm...
                    newTrade.PriceTrade(marketDate);
                    newPF._trades.Add(newTrade.DealID, newTrade);

                }
            }
            return newPF;
        }
 public TradeSet CloneTradeSet()
 {
     TradeSet ret = new TradeSet(this.MyTradeCollection, this.MarketDate);
     ret._trades = new Dictionary<string, Trade>(_trades); // copy references, we do not want to deep clone, i.e. double trade data -- however Options are eventually excercised -- so you cannot go back @@@
     ret.ProductNames = new List<string>(ProductNames);
     return ret;
 }
 public static TradeSet BestGranularityHedge(TradeSet sourcePF)
 {
     throw new NotImplementedException();
 }