/// <summary> /// X = Price , Y = Volume, Z - Hour /// Transform the X and Y values so that they will match a grid structure, /// starting from an uneven structure. /// Assumes ordered points /// </summary> /// <param name="pcms"></param> /// <returns></returns> public List <PriceCurvesModel> NordPoolSpotVolumeCurvesToGrid(List <PriceCurvesModel> pcms) { /* Compute box values */ var minVolumeDemand = pcms.Min(x => x.DemandCurve.Min(y => y.Volume)); var minVolumeSupply = pcms.Min(x => x.SupplyCurve.Min(y => y.Volume)); var minVolume = minVolumeDemand <= minVolumeSupply ? minVolumeDemand : minVolumeSupply; var maxVolumeDemand = pcms.Max(x => x.DemandCurve.Max(y => y.Volume)); var maxVolumeSupply = pcms.Max(x => x.SupplyCurve.Max(y => y.Volume)); var maxVolume = maxVolumeDemand >= maxVolumeSupply ? maxVolumeDemand : maxVolumeSupply; /* Compute granularity */ var maxCountDemand = pcms.Max(x => x.DemandCurve.Count); var maxCountSupply = pcms.Max(x => x.SupplyCurve.Count); var maxCount = maxCountDemand >= maxCountSupply ? maxCountDemand : maxCountSupply; /* Compute values using linear interpolation interpolations */ var volumeStep = (maxVolume - minVolume) / maxCount; var result = new List <PriceCurvesModel>(); foreach (var priceCurvesModel in pcms) { var newPriceCurveModel = new PriceCurvesModel() { Hour = priceCurvesModel.Hour }; /* Must have more than 2 sample points */ if (priceCurvesModel.DemandCurve.Count < 3 || priceCurvesModel.SupplyCurve.Count < 3) { continue; } for (int i = 0; i <= maxCount; i++) { var volume = minVolume + i * volumeStep; var price = Interpolate(priceCurvesModel.DemandCurve, volume); newPriceCurveModel.SupplyCurve.Add(new MarketPoint() { Volume = volume, Price = price }); price = Interpolate(priceCurvesModel.SupplyCurve, volume); newPriceCurveModel.DemandCurve.Add(new MarketPoint() { Volume = volume, Price = price }); } result.Add(newPriceCurveModel); } return(result); }
public PriceCurvesSensitivity(PriceCurvesModel pcm, decimal prc) { _pcm = pcm; _prc = prc; }
public List <PriceCurvesModel> ReadNordPoolSpotPriceCurves(Stream excelFile) { var excelReader = ExcelReaderFactory.CreateBinaryReader(excelFile); var result = excelReader.AsDataSet(); var curves = result.Tables[0]; var demandCurvesStartingPoints = CoordinatesOfTermInTable(curves, "Buy curve"); var supplyCurvesStartingPoints = CoordinatesOfTermInTable(curves, "Sell curve"); if (demandCurvesStartingPoints.Count != supplyCurvesStartingPoints.Count) { throw new Exception("Excel file has inconsistent data"); } var pcmList = new List <PriceCurvesModel>(); for (int i = 0; i < demandCurvesStartingPoints.Count; i++) { var pcm = new PriceCurvesModel() { Hour = i }; var demandPoint = demandCurvesStartingPoints[i]; var demandRow = demandPoint.X + 1; /* Columns are identical, because both are on same column in the spreadsheet */ var col = demandPoint.Y + 1; var supplyRow = supplyCurvesStartingPoints[i].X + 1; /* Demands data */ for (int j = demandRow; j < supplyCurvesStartingPoints[i].X; j += 2) { var price = curves.Rows[j].ItemArray[col].ToString().TryCastToDecimal(); var volume = curves.Rows[j + 1].ItemArray[col].ToString().TryCastToDecimal(); pcm.DemandCurve.Add(new MarketPoint() { Price = price, Volume = volume }); } /* Ensure ordering */ pcm.DemandCurve = pcm.DemandCurve.OrderBy(d => d.Volume).ToList(); /* Supply data */ for (int j = supplyCurvesStartingPoints[i].X + 1; j < curves.Rows.Count; j += 2) { var po = curves.Rows[j].ItemArray[col]; var vo = curves.Rows[j + 1].ItemArray[col]; /* Reached bottom of spreadsheet*/ if (string.IsNullOrEmpty(po.ToString()) || string.IsNullOrEmpty(vo.ToString())) { break; } var price = po.ToString().TryCastToDecimal(); var volume = vo.ToString().TryCastToDecimal(); pcm.SupplyCurve.Add(new MarketPoint() { Price = price, Volume = volume }); } /* Ensure ordering */ pcm.SupplyCurve = pcm.SupplyCurve.OrderBy(d => d.Volume).ToList(); /* Must happen! */ pcm.CalculateEquilibrium(); pcmList.Add(pcm); } return(pcmList); //0.5 seconds for this shit... TOO MUCH! }