proof-of-portfolio 0.0.100__py3-none-any.whl → 0.0.101__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- proof_of_portfolio/_version.py +1 -1
- proof_of_portfolio/circuits/components/src/core/calmar.nr +85 -74
- proof_of_portfolio/circuits/components/src/core/drawdown.nr +96 -22
- proof_of_portfolio/circuits/components/src/core/omega.nr +95 -29
- proof_of_portfolio/circuits/components/src/core/pnl_score.nr +2 -2
- proof_of_portfolio/circuits/components/src/core/sharpe.nr +69 -14
- proof_of_portfolio/circuits/components/src/core/sortino.nr +39 -11
- proof_of_portfolio/circuits/components/src/core/tstat.nr +7 -9
- proof_of_portfolio/circuits/components/src/utils/ann_excess_return.nr +1 -1
- proof_of_portfolio/circuits/components/src/utils/ann_volatility.nr +7 -7
- proof_of_portfolio/circuits/components/src/utils/constants.nr +2 -2
- proof_of_portfolio/circuits/components/src/utils/risk_normalization.nr +4 -1
- proof_of_portfolio/circuits/components/src/utils/sqrt.nr +18 -14
- proof_of_portfolio/circuits/components/src/utils/variance.nr +4 -4
- proof_of_portfolio/circuits/src/main.nr +0 -5
- proof_of_portfolio/circuits/target/circuits.json +1 -1
- proof_of_portfolio/circuits/vk/vk +0 -0
- {proof_of_portfolio-0.0.100.dist-info → proof_of_portfolio-0.0.101.dist-info}/METADATA +1 -1
- {proof_of_portfolio-0.0.100.dist-info → proof_of_portfolio-0.0.101.dist-info}/RECORD +22 -22
- {proof_of_portfolio-0.0.100.dist-info → proof_of_portfolio-0.0.101.dist-info}/WHEEL +0 -0
- {proof_of_portfolio-0.0.100.dist-info → proof_of_portfolio-0.0.101.dist-info}/entry_points.txt +0 -0
- {proof_of_portfolio-0.0.100.dist-info → proof_of_portfolio-0.0.101.dist-info}/top_level.txt +0 -0
@@ -1,8 +1,7 @@
|
|
1
1
|
use crate::utils::{
|
2
|
-
ann_excess_return::ann_excess_return,
|
3
2
|
constants::{
|
4
|
-
ARRAY_SIZE,
|
5
|
-
RATIO_SCALE_FACTOR, SORTINO_DOWNSIDE_MINIMUM, SORTINO_NOCONFIDENCE_VALUE,
|
3
|
+
ARRAY_SIZE, DAYS_IN_YEAR,
|
4
|
+
RATIO_SCALE_FACTOR, SCALE, SORTINO_DOWNSIDE_MINIMUM, SORTINO_NOCONFIDENCE_VALUE,
|
6
5
|
STATISTICAL_CONFIDENCE_MINIMUM_N,
|
7
6
|
},
|
8
7
|
sqrt::sqrt,
|
@@ -11,12 +10,12 @@ use crate::utils::{
|
|
11
10
|
pub fn sortino(
|
12
11
|
log_returns: [i64; ARRAY_SIZE],
|
13
12
|
actual_len: u32,
|
14
|
-
|
13
|
+
_RISK_FREE_RATE: i64,
|
15
14
|
weights: [i64; ARRAY_SIZE],
|
16
15
|
use_weighting: bool,
|
17
16
|
bypass_confidence: bool,
|
18
|
-
|
19
|
-
|
17
|
+
_avg_daily_return: i64,
|
18
|
+
_variance_val: i64,
|
20
19
|
ann_excess_return_val: i64,
|
21
20
|
daily_rf: i64,
|
22
21
|
) -> i64 {
|
@@ -43,7 +42,7 @@ pub fn sortino(
|
|
43
42
|
}
|
44
43
|
}
|
45
44
|
|
46
|
-
if negative_count >
|
45
|
+
if negative_count > 0 {
|
47
46
|
let downside_mean = if use_weighting {
|
48
47
|
if sum_w_down != 0 {
|
49
48
|
weighted_sum_down / sum_w_down
|
@@ -60,7 +59,7 @@ pub fn sortino(
|
|
60
59
|
if (i as u32) < actual_len {
|
61
60
|
if log_returns[i] < daily_rf {
|
62
61
|
let diff = log_returns[i] - downside_mean;
|
63
|
-
let sq_diff =
|
62
|
+
let sq_diff = diff * diff;
|
64
63
|
weighted_sum_sq_diff += sq_diff * weights[i];
|
65
64
|
}
|
66
65
|
}
|
@@ -76,7 +75,7 @@ pub fn sortino(
|
|
76
75
|
if (i as u32) < actual_len {
|
77
76
|
if log_returns[i] < daily_rf {
|
78
77
|
let diff = log_returns[i] - downside_mean;
|
79
|
-
let sq_diff =
|
78
|
+
let sq_diff = diff * diff;
|
80
79
|
sum_sq_diff += sq_diff;
|
81
80
|
}
|
82
81
|
}
|
@@ -88,7 +87,7 @@ pub fn sortino(
|
|
88
87
|
}
|
89
88
|
};
|
90
89
|
|
91
|
-
let annualized_variance = downside_variance_pre * (DAYS_IN_YEAR as i64)
|
90
|
+
let annualized_variance = downside_variance_pre * (DAYS_IN_YEAR as i64);
|
92
91
|
let downside_volatility = sqrt(annualized_variance as u64) as i64;
|
93
92
|
|
94
93
|
let effective_downside_volatility = if downside_volatility > SORTINO_DOWNSIDE_MINIMUM {
|
@@ -155,7 +154,7 @@ fn test_sortino_no_negative_returns() {
|
|
155
154
|
ann_excess,
|
156
155
|
0,
|
157
156
|
);
|
158
|
-
assert(result ==
|
157
|
+
assert(result == SORTINO_NOCONFIDENCE_VALUE);
|
159
158
|
}
|
160
159
|
|
161
160
|
#[test]
|
@@ -211,3 +210,32 @@ fn test_sortino_high_downside_volatility() {
|
|
211
210
|
);
|
212
211
|
assert(result != 0);
|
213
212
|
}
|
213
|
+
|
214
|
+
#[test]
|
215
|
+
fn test_sortino_scaling() {
|
216
|
+
let mut log_returns = [0; ARRAY_SIZE];
|
217
|
+
log_returns[0] = SCALE / 100; // 0.01 * SCALE
|
218
|
+
log_returns[1] = -SCALE / 200; // -0.005 * SCALE
|
219
|
+
let actual_len = 60u32;
|
220
|
+
let risk_free_rate = 0;
|
221
|
+
let weights = [100000; ARRAY_SIZE];
|
222
|
+
let use_weighting = false;
|
223
|
+
let bypass_confidence = true;
|
224
|
+
let avg_daily_return = SCALE / 36500; // 0.01% daily for 1% annual approx
|
225
|
+
let variance_val = 0;
|
226
|
+
let ann_excess_return_val = SCALE / 100; // 1%
|
227
|
+
let daily_rf = 0;
|
228
|
+
let result = sortino(
|
229
|
+
log_returns,
|
230
|
+
actual_len,
|
231
|
+
risk_free_rate,
|
232
|
+
weights,
|
233
|
+
use_weighting,
|
234
|
+
bypass_confidence,
|
235
|
+
avg_daily_return,
|
236
|
+
variance_val,
|
237
|
+
ann_excess_return_val,
|
238
|
+
daily_rf,
|
239
|
+
);
|
240
|
+
assert(result > 0); // scaling test, result should be positive
|
241
|
+
}
|
@@ -1,10 +1,8 @@
|
|
1
1
|
use crate::utils::{
|
2
|
-
average::average,
|
3
2
|
constants::{
|
4
|
-
ARRAY_SIZE,
|
3
|
+
ARRAY_SIZE, STATISTICAL_CONFIDENCE_MINIMUM_N, STATISTICAL_CONFIDENCE_NOCONFIDENCE_VALUE, RATIO_SCALE_FACTOR,
|
5
4
|
},
|
6
5
|
sqrt::sqrt,
|
7
|
-
variance::variance,
|
8
6
|
};
|
9
7
|
|
10
8
|
pub fn statistical_confidence(
|
@@ -15,7 +13,7 @@ pub fn statistical_confidence(
|
|
15
13
|
bypass_confidence: bool,
|
16
14
|
avg_daily_return: i64,
|
17
15
|
variance_val: i64,
|
18
|
-
|
16
|
+
_ann_excess_return_val: i64,
|
19
17
|
) -> i64 {
|
20
18
|
// Check minimum sample size for statistical confidence
|
21
19
|
if !bypass_confidence & actual_len < STATISTICAL_CONFIDENCE_MINIMUM_N {
|
@@ -31,10 +29,10 @@ pub fn statistical_confidence(
|
|
31
29
|
}
|
32
30
|
|
33
31
|
fn compute_t_statistic(
|
34
|
-
|
32
|
+
_log_returns: [i64; ARRAY_SIZE],
|
35
33
|
actual_len: u32,
|
36
|
-
|
37
|
-
|
34
|
+
_weights: [i64; ARRAY_SIZE],
|
35
|
+
_use_weighting: bool,
|
38
36
|
avg_daily_return: i64,
|
39
37
|
variance_val: i64,
|
40
38
|
) -> i64 {
|
@@ -83,7 +81,7 @@ fn test_tstat_insufficient_data() {
|
|
83
81
|
let variance_val = 0;
|
84
82
|
let ann_excess = 365000;
|
85
83
|
let result = statistical_confidence(returns, 1, weights, false, false, avg, variance_val, ann_excess);
|
86
|
-
assert(result ==
|
84
|
+
assert(result == STATISTICAL_CONFIDENCE_NOCONFIDENCE_VALUE);
|
87
85
|
}
|
88
86
|
|
89
87
|
#[test]
|
@@ -98,7 +96,7 @@ fn test_tstat_zero_variance() {
|
|
98
96
|
let variance_val = 0;
|
99
97
|
let ann_excess = 36500;
|
100
98
|
let result = statistical_confidence(returns, 5, weights, false, false, avg, variance_val, ann_excess);
|
101
|
-
assert(result ==
|
99
|
+
assert(result == STATISTICAL_CONFIDENCE_NOCONFIDENCE_VALUE);
|
102
100
|
}
|
103
101
|
|
104
102
|
#[test]
|
@@ -42,11 +42,11 @@ fn test_ann_volatility_zero_variance() {
|
|
42
42
|
#[test]
|
43
43
|
fn test_ann_volatility_positive_variance() {
|
44
44
|
let mut returns = [0; ARRAY_SIZE];
|
45
|
-
returns[0] =
|
46
|
-
returns[1] =
|
47
|
-
returns[2] =
|
48
|
-
returns[3] =
|
49
|
-
returns[4] =
|
45
|
+
returns[0] = 100000;
|
46
|
+
returns[1] = 200000;
|
47
|
+
returns[2] = 300000;
|
48
|
+
returns[3] = 400000;
|
49
|
+
returns[4] = 500000;
|
50
50
|
|
51
51
|
let weights = [100000; ARRAY_SIZE];
|
52
52
|
let result = ann_volatility(returns, 5, weights, false);
|
@@ -63,7 +63,7 @@ fn test_ann_volatility_ddof_zero() {
|
|
63
63
|
let weights = [100000; ARRAY_SIZE];
|
64
64
|
let result_ddof_0 = ann_volatility(returns, 3, weights, false);
|
65
65
|
let result_ddof_1 = ann_volatility(returns, 3, weights, false);
|
66
|
-
assert(result_ddof_0 as i64
|
66
|
+
assert(result_ddof_0 as i64 == result_ddof_1 as i64);
|
67
67
|
}
|
68
68
|
|
69
69
|
#[test]
|
@@ -73,5 +73,5 @@ fn test_ann_volatility_single_value() {
|
|
73
73
|
|
74
74
|
let weights = [100000; ARRAY_SIZE];
|
75
75
|
let result = ann_volatility(returns, 1, weights, false);
|
76
|
-
assert(result ==
|
76
|
+
assert(result == SCALE);
|
77
77
|
}
|
@@ -12,7 +12,7 @@ pub global MERKLE_DEPTH: u32 = 8;
|
|
12
12
|
pub global DAILY_CHECKPOINTS: u32 = 2;
|
13
13
|
pub global SECONDS_PER_DAY: u64 = 86400;
|
14
14
|
|
15
|
-
pub global SCALE: i64 = 100_000_000;
|
15
|
+
pub global SCALE: i64 = 100_000_000; // SCALE: 10^8 for fixed-point precision
|
16
16
|
|
17
17
|
// Date and time constants
|
18
18
|
pub global DAYS_IN_YEAR: i64 = 365;
|
@@ -31,7 +31,7 @@ pub global SORTINO_DOWNSIDE_MINIMUM: i64 = 10_000_000;
|
|
31
31
|
pub global OMEGA_SCALE_FACTOR: i64 = 1000000000;
|
32
32
|
pub global SHARPE_SCALE_FACTOR: i64 = 1000000;
|
33
33
|
pub global LARGE_POSITIVE_VALUE: i64 = 1000000000;
|
34
|
-
pub global RATIO_SCALE_FACTOR: i64 = 1000000;
|
34
|
+
pub global RATIO_SCALE_FACTOR: i64 = 1000000; // RATIO_SCALE_FACTOR: 10^6 for ratio outputs
|
35
35
|
|
36
36
|
pub global CALMAR_NOCONFIDENCE_VALUE: i64 = -100000000;
|
37
37
|
pub global SHARPE_NOCONFIDENCE_VALUE: i64 = -100000000;
|
@@ -9,7 +9,10 @@ pub fn mdd_augmentation(drawdown_decimal: i64, max_drawdown_percentage: i64) ->
|
|
9
9
|
if dd_percent <= 0 | dd_percent >= max_drawdown_percentage {
|
10
10
|
0
|
11
11
|
} else {
|
12
|
-
|
12
|
+
// Risk normalization formula: penalizes drawdown more heavily
|
13
|
+
let penalty = (5 * dd_percent) / 2; // 2.5 * dd_percent
|
14
|
+
let remaining = max_drawdown_percentage - penalty;
|
15
|
+
(remaining * SCALE) / max_drawdown_percentage
|
13
16
|
}
|
14
17
|
}
|
15
18
|
}
|
@@ -9,26 +9,30 @@ unconstrained fn compute_sqrt(n: u64) -> u64 {
|
|
9
9
|
} else if n <= 15 {
|
10
10
|
3
|
11
11
|
} else {
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
// Better initial guess
|
13
|
+
let mut x = n;
|
14
|
+
let mut bit = 1;
|
15
|
+
|
16
|
+
// Find the highest set bit for a better initial guess
|
17
|
+
for _ in 0..32 {
|
18
|
+
bit = bit << 1;
|
19
|
+
if bit > n {
|
20
|
+
break;
|
21
|
+
}
|
22
|
+
}
|
23
|
+
x = bit >> 1;
|
19
24
|
|
20
25
|
if x == 0 {
|
21
26
|
x = 1;
|
22
27
|
}
|
23
28
|
|
24
|
-
|
25
|
-
for _ in 0..
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
x = (x + n / x) / 2;
|
30
|
-
}
|
29
|
+
// Newton-Raphson iteration
|
30
|
+
for _ in 0..20 {
|
31
|
+
let next = (x + n / x) / 2;
|
32
|
+
if next >= x {
|
33
|
+
break;
|
31
34
|
}
|
35
|
+
x = next;
|
32
36
|
}
|
33
37
|
|
34
38
|
x
|
@@ -77,9 +77,9 @@ fn test_variance_same_values() {
|
|
77
77
|
#[test]
|
78
78
|
fn test_variance_different_values() {
|
79
79
|
let mut returns = [0; ARRAY_SIZE];
|
80
|
-
returns[0] =
|
81
|
-
returns[1] =
|
82
|
-
returns[2] =
|
80
|
+
returns[0] = 100000;
|
81
|
+
returns[1] = 200000;
|
82
|
+
returns[2] = 300000;
|
83
83
|
|
84
84
|
let weights = [100000; ARRAY_SIZE];
|
85
85
|
let result = variance(returns, 3, 1, weights, false, 3);
|
@@ -96,7 +96,7 @@ fn test_variance_with_ddof_zero() {
|
|
96
96
|
let weights = [100000; ARRAY_SIZE];
|
97
97
|
let result_ddof_0: i64 = variance(returns, 3, 0, weights, false, 3);
|
98
98
|
let result_ddof_1: i64 = variance(returns, 3, 1, weights, false, 3);
|
99
|
-
assert(result_ddof_0
|
99
|
+
assert(result_ddof_0 == result_ddof_1);
|
100
100
|
}
|
101
101
|
|
102
102
|
#[test]
|
@@ -120,13 +120,8 @@ fn main(
|
|
120
120
|
let calmar_ratio = calmar(
|
121
121
|
returns_array,
|
122
122
|
n_returns,
|
123
|
-
annual_risk_free,
|
124
|
-
weights,
|
125
|
-
use_weighting,
|
126
123
|
bypass_confidence,
|
127
124
|
avg_daily_return,
|
128
|
-
variance_val,
|
129
|
-
ann_excess_return_val,
|
130
125
|
calmar_cap,
|
131
126
|
days_in_year,
|
132
127
|
drawdown_max_percent,
|