148 lines
4.3 KiB
C#
Executable File
148 lines
4.3 KiB
C#
Executable File
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
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;
|
|
for (double value = minValue; value < maxValue; value += binSize)
|
|
{
|
|
binItems.Add(new BinItem<T>(value));
|
|
}
|
|
for (int index = 0; index < values.Length; index++)
|
|
{
|
|
AddValueToBin(values[index]);
|
|
AddObjectToBin(values[index],items[index]);
|
|
}
|
|
double samplesAtRank = samples-(samples * (percentile/100.00));
|
|
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;
|
|
for (double value = minValue; value < maxValue; value += binSize)
|
|
{
|
|
binItems.Add(new BinItem<T>(value));
|
|
}
|
|
for (int index = 0; index < values.Length; index++)
|
|
{
|
|
AddValueToBin(values[index]);
|
|
}
|
|
double samplesAtRank = samples-(samples * (percentile/100.00));
|
|
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 (0 == index)
|
|
{
|
|
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 (false == added && binItems.Count>0) binItems[binItems.Count - 1].BinCount++;
|
|
}
|
|
private void AddObjectToBin(double value,T item)
|
|
{
|
|
bool added = false;
|
|
// samples++;
|
|
for (int index = 0; index < binItems.Count; index++)
|
|
{
|
|
BinItem<T> binItem = binItems[index];
|
|
if (value <= binItem.BinValue)
|
|
{
|
|
binItem.BinObject=item;
|
|
added = true;
|
|
break;
|
|
}
|
|
}
|
|
if (false == added && binItems.Count>0) binItems[binItems.Count - 1].BinObject=item;
|
|
}
|
|
}
|
|
}
|