180 lines
5.1 KiB
C#
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;
|
|
}
|
|
}
|
|
} |