proof-of-portfolio 0.0.99__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 +98 -31
- 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 +47 -14
- 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 +3 -5
- proof_of_portfolio/circuits/target/circuits.json +1 -1
- proof_of_portfolio/circuits/vk/vk +0 -0
- proof_of_portfolio/proof_generator.py +5 -0
- {proof_of_portfolio-0.0.99.dist-info → proof_of_portfolio-0.0.101.dist-info}/METADATA +1 -1
- {proof_of_portfolio-0.0.99.dist-info → proof_of_portfolio-0.0.101.dist-info}/RECORD +23 -23
- {proof_of_portfolio-0.0.99.dist-info → proof_of_portfolio-0.0.101.dist-info}/WHEEL +0 -0
- {proof_of_portfolio-0.0.99.dist-info → proof_of_portfolio-0.0.101.dist-info}/entry_points.txt +0 -0
- {proof_of_portfolio-0.0.99.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,13 +10,14 @@ 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,
|
20
|
+
daily_rf: i64,
|
21
21
|
) -> i64 {
|
22
22
|
if !bypass_confidence & actual_len < STATISTICAL_CONFIDENCE_MINIMUM_N {
|
23
23
|
SORTINO_NOCONFIDENCE_VALUE
|
@@ -31,7 +31,7 @@ pub fn sortino(
|
|
31
31
|
|
32
32
|
for i in 0..ARRAY_SIZE {
|
33
33
|
if (i as u32) < actual_len {
|
34
|
-
if log_returns[i] <
|
34
|
+
if log_returns[i] < daily_rf {
|
35
35
|
downside_returns_sum += log_returns[i];
|
36
36
|
negative_count += 1;
|
37
37
|
if use_weighting {
|
@@ -42,7 +42,7 @@ pub fn sortino(
|
|
42
42
|
}
|
43
43
|
}
|
44
44
|
|
45
|
-
if negative_count >
|
45
|
+
if negative_count > 0 {
|
46
46
|
let downside_mean = if use_weighting {
|
47
47
|
if sum_w_down != 0 {
|
48
48
|
weighted_sum_down / sum_w_down
|
@@ -57,9 +57,9 @@ pub fn sortino(
|
|
57
57
|
let mut weighted_sum_sq_diff: i64 = 0;
|
58
58
|
for i in 0..ARRAY_SIZE {
|
59
59
|
if (i as u32) < actual_len {
|
60
|
-
if log_returns[i] <
|
60
|
+
if log_returns[i] < daily_rf {
|
61
61
|
let diff = log_returns[i] - downside_mean;
|
62
|
-
let sq_diff =
|
62
|
+
let sq_diff = diff * diff;
|
63
63
|
weighted_sum_sq_diff += sq_diff * weights[i];
|
64
64
|
}
|
65
65
|
}
|
@@ -73,9 +73,9 @@ pub fn sortino(
|
|
73
73
|
let mut sum_sq_diff: i64 = 0;
|
74
74
|
for i in 0..ARRAY_SIZE {
|
75
75
|
if (i as u32) < actual_len {
|
76
|
-
if log_returns[i] <
|
76
|
+
if log_returns[i] < daily_rf {
|
77
77
|
let diff = log_returns[i] - downside_mean;
|
78
|
-
let sq_diff =
|
78
|
+
let sq_diff = diff * diff;
|
79
79
|
sum_sq_diff += sq_diff;
|
80
80
|
}
|
81
81
|
}
|
@@ -87,7 +87,7 @@ pub fn sortino(
|
|
87
87
|
}
|
88
88
|
};
|
89
89
|
|
90
|
-
let annualized_variance = downside_variance_pre * (DAYS_IN_YEAR as i64)
|
90
|
+
let annualized_variance = downside_variance_pre * (DAYS_IN_YEAR as i64);
|
91
91
|
let downside_volatility = sqrt(annualized_variance as u64) as i64;
|
92
92
|
|
93
93
|
let effective_downside_volatility = if downside_volatility > SORTINO_DOWNSIDE_MINIMUM {
|
@@ -126,6 +126,7 @@ fn test_sortino_normal_case() {
|
|
126
126
|
avg,
|
127
127
|
variance_val,
|
128
128
|
ann_excess,
|
129
|
+
0,
|
129
130
|
);
|
130
131
|
assert(result != 0);
|
131
132
|
}
|
@@ -151,8 +152,9 @@ fn test_sortino_no_negative_returns() {
|
|
151
152
|
avg,
|
152
153
|
variance_val,
|
153
154
|
ann_excess,
|
155
|
+
0,
|
154
156
|
);
|
155
|
-
assert(result ==
|
157
|
+
assert(result == SORTINO_NOCONFIDENCE_VALUE);
|
156
158
|
}
|
157
159
|
|
158
160
|
#[test]
|
@@ -176,6 +178,7 @@ fn test_sortino_all_negative_returns() {
|
|
176
178
|
avg,
|
177
179
|
variance_val,
|
178
180
|
ann_excess,
|
181
|
+
0,
|
179
182
|
);
|
180
183
|
assert(result != 0);
|
181
184
|
}
|
@@ -203,6 +206,36 @@ fn test_sortino_high_downside_volatility() {
|
|
203
206
|
avg,
|
204
207
|
variance_val,
|
205
208
|
ann_excess,
|
209
|
+
0,
|
206
210
|
);
|
207
211
|
assert(result != 0);
|
208
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]
|
@@ -29,6 +29,7 @@ fn main(
|
|
29
29
|
days_in_year: i64,
|
30
30
|
omega_loss_min: i64,
|
31
31
|
annual_risk_free: i64,
|
32
|
+
daily_rf: i64,
|
32
33
|
drawdown_max_percent: i64,
|
33
34
|
) -> pub [Field; 9] {
|
34
35
|
// Verify all trading signals are included in the merkle tree
|
@@ -119,13 +120,8 @@ fn main(
|
|
119
120
|
let calmar_ratio = calmar(
|
120
121
|
returns_array,
|
121
122
|
n_returns,
|
122
|
-
annual_risk_free,
|
123
|
-
weights,
|
124
|
-
use_weighting,
|
125
123
|
bypass_confidence,
|
126
124
|
avg_daily_return,
|
127
|
-
variance_val,
|
128
|
-
ann_excess_return_val,
|
129
125
|
calmar_cap,
|
130
126
|
days_in_year,
|
131
127
|
drawdown_max_percent,
|
@@ -137,6 +133,7 @@ fn main(
|
|
137
133
|
use_weighting,
|
138
134
|
bypass_confidence,
|
139
135
|
omega_loss_min,
|
136
|
+
daily_rf,
|
140
137
|
);
|
141
138
|
let sortino_ratio = sortino(
|
142
139
|
returns_array,
|
@@ -148,6 +145,7 @@ fn main(
|
|
148
145
|
avg_daily_return,
|
149
146
|
variance_val,
|
150
147
|
ann_excess_return_val,
|
148
|
+
daily_rf,
|
151
149
|
);
|
152
150
|
let stat_confidence = statistical_confidence(
|
153
151
|
returns_array,
|