public CreateCountryBondFlysForMaturityGaps(string[] folderPath_, string text_, BondMarket market_, uint unitGap_, MaturityGapUnit unitType_, BondFlyWeightMode mode_)
   : base(folderPath_,text_)
 {
   Market = market_;
   UnitGap = unitGap_;
   MyMode = mode_;
   UnitType = unitType_;
 }
 public static void AddMicroGrapFlys(string[] addToThisFolderPath_, BondMarket market_, BondFlyWeightMode mode_ = BondFlyWeightMode.WithinMonthNonWeighted)
 {
   foreach(var tenor in new[] {6})
   {
     var folderPath = addToThisFolderPath_.Concat(new string[] { "MicroGap Flys", string.Format("{0}M Wings", tenor) }).ToArray();
     CreateIntraCountryMaturityGapBondFlies(folderPath, market_, (uint)tenor, MaturityGapUnit.Months, BondFlyWeightMode.WithinAThirdNonWeighted);
   }
   foreach (var tenor in new[] { 1, 2, 3, 5 })
   {
     var folderPath = addToThisFolderPath_.Concat(new string[] { "MicroGap Flys", string.Format("{0}Y Wings", tenor) }).ToArray();
     CreateIntraCountryMaturityGapBondFlies(folderPath, market_, (uint)tenor, MaturityGapUnit.Years, mode_);
   }
 }
    public static async void CreateIntraCountryMaturityGapBondFlies(string[] folderPath_, BondMarket market_, uint unitGap_, MaturityGapUnit unitType_, BondFlyWeightMode mode_)
    {
      var source = CountryBondSource.GetInstance(market_);

      var newDefinitions = new List<BondStructureDefinition>();

      foreach (var bond in source.Lines)
      {
        var idealPriorDate = (unitType_ == MaturityGapUnit.Years)
          ? bond.Maturity.AddYears(-(int) unitGap_)
          : bond.Maturity.AddMonths(-(int) unitGap_);
        var priorBond = findBestBond(bond, idealPriorDate, source.Lines, mode_, (int) unitGap_, unitType_);
        if (priorBond == null) continue;

        var idealLatterDate = (unitType_ == MaturityGapUnit.Years)
          ? bond.Maturity.AddYears((int) unitGap_)
          : bond.Maturity.AddMonths((int) unitGap_);
        var latterBond = findBestBond(bond, idealLatterDate, source.Lines, mode_, (int) unitGap_, unitType_);
        if (latterBond == null) continue;

        var priorWeighting = StructureWeightings.Bfly_Wing;
        var latterWeighting = StructureWeightings.Bfly_Wing;

        if (mode_ == BondFlyWeightMode.WithinAThirdWeighted)
        {
          var priorLevel = priorBond.GetValue(BondField.YieldLive);
          var level = bond.GetValue(BondField.YieldLive);
          var latterLevel = latterBond.GetValue(BondField.YieldLive);

          {
            var yieldDiff = level - priorLevel;
            var maturityDiff = (bond.Maturity - priorBond.Maturity).TotalDays / 365.25d;
            var desiredLevel = level - (maturityDiff / Convert.ToDouble(unitGap_) * yieldDiff);
            var levelAdjustment = desiredLevel / priorLevel;
            priorWeighting *= levelAdjustment;
          }
          {
            var yieldDiff = latterLevel - level;
            var maturityDiff = (latterBond.Maturity - bond.Maturity).TotalDays / 365.25d;
            var desiredLevel = level + (maturityDiff / Convert.ToDouble(unitGap_) * yieldDiff);
            var levelAdjustment = desiredLevel / latterLevel;
            latterWeighting *= levelAdjustment;
          }
        }

        var newDef = new BondStructureDefinition()
        {
          FolderTree = folderPath_,
          Items = new System.ComponentModel.BindingList<BondStructureDefinitionItem>(
            new[]
            {
              BondStructureDefinitionItem.GetDefinition(priorBond, priorWeighting),
              BondStructureDefinitionItem.GetDefinition(bond, StructureWeightings.Bfly_Belly),
              BondStructureDefinitionItem.GetDefinition(latterBond, latterWeighting)
            }.ToList()),
          Name =
            string.Format("{0} {1} {2} {3}{4}", market_, priorBond.Maturity.ToString("MM/yy"),
              bond.Maturity.ToString("MM/yy"), latterBond.Maturity.ToString("MM/yy"),
              mode_ == BondFlyWeightMode.WithinAThirdWeighted ? " (w)" : string.Empty),
          Owner = SymmetryEnvironment.UserName
        };

        if (!newDefinitions.Any(x => x.Name.Equals(newDef.Name)))
          newDefinitions.Add(newDef);
      }

      await Singleton<BondStructureDefinitionCache>.Instance.AddOrUpdateDefinitions(newDefinitions);

    }
    private static BondAnalysisLine findBestBond(BondAnalysisLine bellyBond_, DateTime perfectDate_, IEnumerable<BondAnalysisLine> candidates_, BondFlyWeightMode mode_, int unitGap_, MaturityGapUnit unitType_)
    {
      DateTime fromDate = perfectDate_, toDate = perfectDate_;
      switch (mode_)
      {
        case BondFlyWeightMode.WithinMonthNonWeighted:
          {
            if (unitType_ == MaturityGapUnit.Years && bellyBond_.TimeToMaturity >= 10)
            {
              fromDate = perfectDate_.AddYears(-1);
              toDate = perfectDate_.AddYears(1);
            }
            else
            {
              fromDate = perfectDate_.AddMonths(-1);
              toDate = perfectDate_.AddMonths(1);
            }
          }
          break;
        case BondFlyWeightMode.WithinAThirdWeighted:
        case BondFlyWeightMode.WithinAThirdNonWeighted:
          {
            if (unitType_ == MaturityGapUnit.Years)
            {
              fromDate = perfectDate_.AddMonths(-Convert.ToInt32(unitGap_ * 12 / 3));
              toDate = perfectDate_.AddMonths(Convert.ToInt32(unitGap_ * 12 / 3));
            }
            else if (unitType_ == MaturityGapUnit.Months)
            {
              fromDate = perfectDate_.AddMonths(-Convert.ToInt32(unitGap_/3));
              toDate = perfectDate_.AddMonths(Convert.ToInt32(unitGap_/3));
            }
          }
          break;
      }

      var best2 =
        candidates_.Where(
          x =>
            // within maturity range
            x.Maturity >= fromDate && x.Maturity <= toDate &&
            // not the belly bond
            String.Compare(x.UnderlyingBond.Isin, bellyBond_.UnderlyingBond.Isin, StringComparison.OrdinalIgnoreCase) !=
            0)
          .Select(x => new {Gap = Math.Abs((perfectDate_ - x.Maturity).TotalDays), Candidate = x})
          // ordered by the gap to the perfect date
          .OrderBy(x => x.Gap)
          .Take(2).ToArray();

      if (best2 == null || best2.Length == 0) return null;

      if (best2.Length == 1)
        return best2[0].Candidate;

      // if there are 2 bonds maturing in the same month, then return the lower coupon one 
      if (best2[0].Candidate.Maturity.Year == best2[1].Candidate.Maturity.Year
        && best2[0].Candidate.Maturity.Month == best2[1].Candidate.Maturity.Month)
      {
        return best2.OrderBy(x => x.Candidate.UnderlyingBond.Coupon).First().Candidate;
      }

      return best2[0].Candidate;
    }