Files
marketdata/MarketDataLib/ValueAtRisk/BinManager.cs

180 lines
5.1 KiB
C#

using System.Collections.Generic;
namespace MarketData.ValueAtRisk
{
public class BinResult<T>
{
public double Value { get; private set; }
public T Item { get; private set; }
public BinResult() { }
public BinResult(double value, T item)
{
this.Value = value;
this.Item = item;
}
}
public class BinManager<T>
{
private List<BinItem<T>> binItems;
private long binCount;
private long samples;
public BinManager(long binCount = 100)
{
this.binCount = binCount;
InitializeBins();
}
private void InitializeBins()
{
this.binItems = new List<BinItem<T>>();
this.samples = 0;
}
public BinResult<T> GetVaRReturn(double[] values, List<T> items, double percentile)
{
double minValue = float.NaN;
double maxValue = float.NaN;
double binSize = double.NaN;
T item = default(T);
InitializeBins();
GetMinMax(ref minValue, ref maxValue, values);
binSize = (maxValue - minValue) / (double)binCount;
if (binSize == 0) binSize = 1e-10;
// Create bins
for (double value = minValue; value <= maxValue; value += binSize)
{
binItems.Add(new BinItem<T>(value));
}
// Add values and objects to bins
for (int index = 0; index < values.Length; index++)
{
AddValueToBin(values[index]);
AddObjectToBin(values[index], items[index]);
}
double samplesAtRank = samples - (samples * (percentile / 100.0));
if (samplesAtRank < 1) samplesAtRank = 1;
long samplesInRank = 0;
double percentVaR = 0;
for (int index = 0; index < binItems.Count; index++)
{
BinItem<T> binItem = binItems[index];
samplesInRank += binItem.BinCount;
percentVaR = binItem.BinValue;
item = binItem.BinObject;
if (samplesInRank > samplesAtRank) break;
}
return new BinResult<T>(percentVaR, item);
}
public double GetVaRReturn(double[] values, double percentile)
{
double minValue = float.NaN;
double maxValue = float.NaN;
double binSize = double.NaN;
InitializeBins();
GetMinMax(ref minValue, ref maxValue, values);
binSize = (maxValue - minValue) / (double)binCount;
if (binSize == 0) binSize = 1e-10;
// Create bins
for (double value = minValue; value <= maxValue; value += binSize)
{
binItems.Add(new BinItem<T>(value));
}
// Add values to bins
for (int index = 0; index < values.Length; index++)
{
AddValueToBin(values[index]);
}
double samplesAtRank = samples - (samples * (percentile / 100.0));
if (samplesAtRank < 1) samplesAtRank = 1;
long samplesInRank = 0;
double percentVaR = 0;
for (int index = 0; index < binItems.Count; index++)
{
BinItem<T> binItem = binItems[index];
samplesInRank += binItem.BinCount;
percentVaR = binItem.BinValue;
if (samplesInRank > samplesAtRank) break;
}
return percentVaR;
}
private static void GetMinMax(ref double minValue, ref double maxValue, double[] values)
{
for (int index = 0; index < values.Length; index++)
{
double value = values[index];
if (index == 0)
{
minValue = maxValue = value;
continue;
}
if (value > maxValue) maxValue = value;
if (value < minValue) minValue = value;
}
}
private void AddValueToBin(double value)
{
bool added = false;
samples++;
for (int index = 0; index < binItems.Count; index++)
{
BinItem<T> binItem = binItems[index];
if (value <= binItem.BinValue)
{
binItem.BinCount++;
added = true;
break;
}
}
if (!added && binItems.Count > 0)
binItems[binItems.Count - 1].BinCount++;
}
private void AddObjectToBin(double value, T item)
{
bool added = false;
for (int index = 0; index < binItems.Count; index++)
{
BinItem<T> binItem = binItems[index];
if (value <= binItem.BinValue)
{
binItem.BinObject = item;
added = true;
break;
}
}
if (!added && binItems.Count > 0)
binItems[binItems.Count - 1].BinObject = item;
}
}
}