Compare commits

...
Author SHA1 Message Date
Taha a359e2a803 Fixing PNL for both crypto and non crypto 2025-02-19 23:28:07 -05:00
+101 -30
View File
@@ -4,6 +4,9 @@ using bts.api;
using BCG;
using mbts.co2;
using System.Xml.Serialization;
using ZstdSharp.Unsafe;
using bts.proto;
namespace mbts.analytics {
// Pairs ITradeLogRow along with the data (theo, md) that is needed to compute
@@ -18,20 +21,87 @@ namespace mbts.analytics {
public SecurityImmutable security { get { return md.security; } }
private double _option_pnl(double trade_price, double now_price) {
double coin_terms = (now_price - trade_price) * tl_row.size;
double usd_terms = coin_terms * driver;
return usd_terms;
// private double _option_pnl(double trade_price, double now_price) {
// double coin_terms = (now_price - trade_price) * tl_row.size;
// double usd_terms = coin_terms * driver;
// return usd_terms;
// }
private bool _is_notional {
get {
return false;
}
}
private double _future_pnl(double trade_price, double now_price) {
// the qty is in USD, so this is the initial cash flow
double init_asset_value = tl_row.size;
double asset_size = init_asset_value / tl_row.price;
double now_asset_value = asset_size * now_price;
return now_asset_value - init_asset_value;
private bool _is_inverse_option_contract {
get {
return false;
}
}
private double _cpp {
get {
return 1.0;
}
}
private bool _is_reverse_option_contract {
get {
// check for Deribit options
return false;
}
}
private double _option_pnl {
get {
if (_is_notional) {
var now_price = theo;
double coin_terms = (now_price - tl_row.price) * tl_row.size;
double usd_terms = coin_terms * driver;
return usd_terms;
} else {
return _cpp * tl_row.size * (theo - tl_row.price);
}
}
}
private double _spot_pnl {
get {
// both are computed the same way
return _future_pnl;
}
}
private double _future_pnl {
get {
if (_is_notional) {
// TODO:
// let it fall through right now
// the qty is in USD, so this is the initial cash flow
var now_price = theo;
double init_asset_value = tl_row.size;
double asset_size = init_asset_value / tl_row.price;
double now_asset_value = asset_size * now_price;
return now_asset_value - init_asset_value;
} else {
// TODO: is position pnl, compute it wrt settlement price?
return tl_row.size * (theo - tl_row.price);
}
}
}
// private double _future_pnl(double trade_price, double now_price) {
// if (_is_notional) {
// // the qty is in USD, so this is the initial cash flow
// double init_asset_value = tl_row.size;
// double asset_size = init_asset_value / tl_row.price;
// double now_asset_value = asset_size * now_price;
// return now_asset_value - init_asset_value;
// } else {
// return tl_row.size * (theo - tl_row.price);
// }
// }
public double driver {
get {
@@ -46,9 +116,16 @@ namespace mbts.analytics {
public double theo {
get {
switch (tl_row.security_type) {
// TODO:
case SecurityType.Option:
return tl_row.call_put == PutOrCall.Call ?
opt_theo.fwd_normalized_call : opt_theo.fwd_normalized_put;
if (_is_inverse_option_contract) {
return tl_row.call_put == PutOrCall.Call ?
opt_theo.fwd_normalized_call : opt_theo.fwd_normalized_put;
} else {
return tl_row.call_put == PutOrCall.Call ?
opt_theo.call : opt_theo.put;
}
// future and options, just get mid market
case SecurityType.Future:
//return fut_theo.theo;
case SecurityType.Spot:
@@ -62,28 +139,22 @@ namespace mbts.analytics {
public double pnl {
get {
double rv = Double.NaN;
if (is_day_trade) {
if (tl_row.security_type == SecurityType.Future) {
rv = _future_pnl(tl_row.price, theo);
} else if (tl_row.security_type == SecurityType.Option) {
rv = _option_pnl(tl_row.price, theo);
} else if (tl_row.security_type == SecurityType.Spot) {
rv = tl_row.size * (theo - tl_row.price);
}
return rv;
switch (tl_row.security_type) {
case SecurityType.Option:
rv = _option_pnl;
break;
case SecurityType.Future:
rv = _future_pnl;
break;
case SecurityType.Spot:
// = tl_row.size * (theo - tl_row.price);
rv = _spot_pnl;
break;
}
// use settle price ?
if (tl_row.security_type == SecurityType.Future) {
rv = _future_pnl(tl_row.price, theo);
} else if (tl_row.security_type == SecurityType.Option) {
rv = _option_pnl(tl_row.price, theo);
} else if (tl_row.security_type == SecurityType.Spot) {
rv = tl_row.size * tl_row.price - settle_price;
}
return rv;
}
}
public double settle_price {
get {
return md.md == null ? Double.NaN : md.md.settlement_price;