He implementado una clase en C# que calculará las pérdidas y ganancias en función de esta descripción de TT. Sin embargo, me preocupa que dé resultados diferentes para los mismos rellenos, si se aplican los cálculos de "descarga de rellenos" frente a si simplemente se añaden rellenos (ejemplo de abajo).
¿Existe un recurso de referencia claro para el cálculo de las pérdidas y ganancias? Google me ha fallado significativamente en este caso. Incluyo el código en caso de que esto puede dar una idea de un error.
public sealed class ProfitLoss
{
public double Realized { get; private set; }
public int Net { get; private set; }
public double AverageOpenPrice { get; private set; }
public ProfitLoss()
{
}
public ProfitLoss(IEnumerable<Tuple<int, double>> initial)
{
int buyQuantity = 0, sellQuantity = 0;
double averageBuyPrice = 0, averageSellPrice = 0;
foreach (var fill in initial)
{
if (fill.Item1 > 0)
{
buyQuantity += fill.Item1;
averageBuyPrice += fill.Item1 * fill.Item2;
}
else if (fill.Item1 < 0)
{
int absQuantity = Math.Abs(fill.Item1);
sellQuantity += absQuantity;
averageSellPrice += absQuantity * fill.Item2;
}
}
if (buyQuantity > 0)
averageBuyPrice /= buyQuantity;
if (sellQuantity > 0)
averageSellPrice /= sellQuantity;
Net = buyQuantity - sellQuantity;
AverageOpenPrice = Net > 0 ? averageBuyPrice : averageSellPrice;
Realized = (averageSellPrice - averageBuyPrice) * Math.Min(buyQuantity, sellQuantity);
}
public void AddFill(int quantity, double price)
{
if (quantity == 0)
throw new ArgumentOutOfRangeException(nameof(quantity), "Quantity must be non-zero.");
if (Math.Sign(Net) != Math.Sign(quantity))
{
int absNet = Math.Abs(Net);
int absQuantity = Math.Abs(quantity);
if (absNet == absQuantity) // flat
{
Realized += (price - AverageOpenPrice) * Net;
AverageOpenPrice = 0;
}
else if (absNet > absQuantity) // decrease
{
Realized += (price - AverageOpenPrice) * -quantity;
}
else // reverse
{
Realized += (price - AverageOpenPrice) * Net;
AverageOpenPrice = price;
}
}
else // increase position
{
AverageOpenPrice = (Net * AverageOpenPrice + quantity * price) / (Net + quantity);
}
Net += quantity;
}
public double FloatingForTheoriticalExit(double exitPrice)
{
return (exitPrice - AverageOpenPrice) * Net;
}
}
Ejemplo de diferencia de cálculo:
new ProfitLoss(new[] {
Tuple.Create(12, 100.0),
Tuple.Create(17, 99.0),
Tuple.Create(-9, 101.0),
Tuple.Create(-4, 105.0),
Tuple.Create(3, 103.0)
}).Dump();
Rendimientos:
Realized 32.2499999999999
Net 19
AverageOpenPrice 99.75
Pero
var calc = new ProfitLoss();
calc.AddFill(12, 100);
calc.AddFill(17, 99);
calc.AddFill(-9, 101);
calc.AddFill(-4, 105);
calc.AddFill(3, 103);
calc.Dump();
Rendimientos:
Realized 36.6206896551725
Net 19
AverageOpenPrice 99.9800362976407