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
proof_of_portfolio/_version.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
# This file is auto-generated during build
|
2
|
-
__version__ = "0.0.
|
2
|
+
__version__ = "0.0.101"
|
@@ -10,13 +10,8 @@ use super::drawdown::daily_max_drawdown;
|
|
10
10
|
pub fn calmar(
|
11
11
|
log_returns: [i64; ARRAY_SIZE],
|
12
12
|
actual_len: u32,
|
13
|
-
annual_risk_free: i64,
|
14
|
-
weights: [i64; ARRAY_SIZE],
|
15
|
-
use_weighting: bool,
|
16
13
|
bypass_confidence: bool,
|
17
14
|
avg_daily_return: i64,
|
18
|
-
variance_val: i64,
|
19
|
-
ann_excess_return_val: i64,
|
20
15
|
calmar_cap: i64,
|
21
16
|
days_in_year: i64,
|
22
17
|
drawdown_max_percent: i64,
|
@@ -25,7 +20,7 @@ pub fn calmar(
|
|
25
20
|
CALMAR_NOCONFIDENCE_VALUE
|
26
21
|
} else {
|
27
22
|
let base_return_percentage = (avg_daily_return * days_in_year * 100) / SCALE;
|
28
|
-
let max_drawdown_decimal = daily_max_drawdown(log_returns, actual_len);
|
23
|
+
let max_drawdown_decimal = daily_max_drawdown(log_returns, actual_len) / SCALE;
|
29
24
|
let drawdown_normalization_factor =
|
30
25
|
risk_normalization(max_drawdown_decimal, drawdown_max_percent);
|
31
26
|
|
@@ -54,24 +49,8 @@ fn test_calmar_normal_case() {
|
|
54
49
|
returns[i] = if i % 2 == 0 { 200 } else { -150 };
|
55
50
|
}
|
56
51
|
|
57
|
-
let weights = [100000; ARRAY_SIZE];
|
58
52
|
let avg = 25;
|
59
|
-
let
|
60
|
-
let ann_excess = 9025;
|
61
|
-
let result = calmar(
|
62
|
-
returns,
|
63
|
-
40,
|
64
|
-
100,
|
65
|
-
weights,
|
66
|
-
false,
|
67
|
-
false,
|
68
|
-
avg,
|
69
|
-
variance_val,
|
70
|
-
ann_excess,
|
71
|
-
1,
|
72
|
-
365,
|
73
|
-
10,
|
74
|
-
);
|
53
|
+
let result = calmar(returns, 40, false, avg, 1, 365, 10);
|
75
54
|
assert(result != 0);
|
76
55
|
}
|
77
56
|
|
@@ -81,25 +60,9 @@ fn test_calmar_insufficient_data() {
|
|
81
60
|
returns[0] = 1000;
|
82
61
|
returns[1] = -500;
|
83
62
|
|
84
|
-
let weights = [100000; ARRAY_SIZE];
|
85
63
|
let avg = 250;
|
86
|
-
let
|
87
|
-
|
88
|
-
let result = calmar(
|
89
|
-
returns,
|
90
|
-
2,
|
91
|
-
100,
|
92
|
-
weights,
|
93
|
-
false,
|
94
|
-
false,
|
95
|
-
avg,
|
96
|
-
variance_val,
|
97
|
-
ann_excess,
|
98
|
-
1,
|
99
|
-
365,
|
100
|
-
10,
|
101
|
-
);
|
102
|
-
assert(result == 0);
|
64
|
+
let result = calmar(returns, 2, false, avg, 1, 365, 10);
|
65
|
+
assert(result == CALMAR_NOCONFIDENCE_VALUE);
|
103
66
|
}
|
104
67
|
|
105
68
|
#[test]
|
@@ -109,24 +72,8 @@ fn test_calmar_exactly_30_days() {
|
|
109
72
|
returns[i] = 100;
|
110
73
|
}
|
111
74
|
|
112
|
-
let weights = [100000; ARRAY_SIZE];
|
113
75
|
let avg = 100;
|
114
|
-
let
|
115
|
-
let ann_excess = 36450;
|
116
|
-
let result = calmar(
|
117
|
-
returns,
|
118
|
-
30,
|
119
|
-
50,
|
120
|
-
weights,
|
121
|
-
false,
|
122
|
-
false,
|
123
|
-
avg,
|
124
|
-
variance_val,
|
125
|
-
ann_excess,
|
126
|
-
1,
|
127
|
-
365,
|
128
|
-
10,
|
129
|
-
);
|
76
|
+
let result = calmar(returns, 30, false, avg, 1, 365, 10);
|
130
77
|
assert(result != 0);
|
131
78
|
}
|
132
79
|
|
@@ -137,23 +84,87 @@ fn test_calmar_negative_returns() {
|
|
137
84
|
returns[i] = -100;
|
138
85
|
}
|
139
86
|
|
140
|
-
let weights = [100000; ARRAY_SIZE];
|
141
87
|
let avg = -100;
|
142
|
-
let
|
143
|
-
|
88
|
+
let result = calmar(returns, 50, false, avg, 1, 365, 10);
|
89
|
+
assert(result != 0);
|
90
|
+
}
|
91
|
+
|
92
|
+
#[test]
|
93
|
+
fn test_calmar_scaling() {
|
94
|
+
let mut log_returns = [0; ARRAY_SIZE];
|
95
|
+
log_returns[0] = SCALE / 100;
|
96
|
+
log_returns[1] = -SCALE / 200;
|
97
|
+
let actual_len = 60u32;
|
98
|
+
let bypass_confidence = true;
|
99
|
+
let avg_daily_return = SCALE / 100;
|
100
|
+
let calmar_cap = 10;
|
101
|
+
let days_in_year = 365;
|
102
|
+
let drawdown_max_percent = 10;
|
144
103
|
let result = calmar(
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
variance_val,
|
153
|
-
ann_excess,
|
154
|
-
1,
|
155
|
-
365,
|
156
|
-
10,
|
104
|
+
log_returns,
|
105
|
+
actual_len,
|
106
|
+
bypass_confidence,
|
107
|
+
avg_daily_return,
|
108
|
+
calmar_cap,
|
109
|
+
days_in_year,
|
110
|
+
drawdown_max_percent,
|
157
111
|
);
|
158
|
-
|
112
|
+
|
113
|
+
assert(result >= 0);
|
114
|
+
}
|
115
|
+
|
116
|
+
#[test]
|
117
|
+
fn test_calmar_parity() {
|
118
|
+
let mut returns = [0; ARRAY_SIZE];
|
119
|
+
returns[0] = 2000000i64;
|
120
|
+
returns[1] = -1000000i64;
|
121
|
+
returns[2] = 1000000i64;
|
122
|
+
let avg = 666667i64;
|
123
|
+
let result = calmar(returns, 3u32, true, avg, 1i64, 365i64, 10i64);
|
124
|
+
let expected = 1000000i64;
|
125
|
+
let diff = if result > expected {
|
126
|
+
result - expected
|
127
|
+
} else {
|
128
|
+
expected - result
|
129
|
+
};
|
130
|
+
assert(diff >= 0);
|
131
|
+
}
|
132
|
+
|
133
|
+
#[test]
|
134
|
+
fn test_calmar_less_than_60_days() {
|
135
|
+
let mut returns = [0; ARRAY_SIZE];
|
136
|
+
returns[0] = 1000000i64;
|
137
|
+
let avg = 1000000i64;
|
138
|
+
let result = calmar(returns, 59u32, false, avg, 1i64, 365i64, 10i64);
|
139
|
+
assert(result == -100000000i64);
|
140
|
+
}
|
141
|
+
|
142
|
+
#[test]
|
143
|
+
fn test_calmar_zero_variance() {
|
144
|
+
let mut returns = [0; ARRAY_SIZE];
|
145
|
+
let avg = 0i64;
|
146
|
+
let result = calmar(returns, 60u32, true, avg, 1i64, 365i64, 10i64);
|
147
|
+
assert(result == 0i64);
|
148
|
+
}
|
149
|
+
|
150
|
+
#[test]
|
151
|
+
fn test_calmar_all_positive() {
|
152
|
+
let mut returns = [0; ARRAY_SIZE];
|
153
|
+
for i in 0..60 {
|
154
|
+
returns[i] = 1000000i64;
|
155
|
+
}
|
156
|
+
let avg = 1000000i64;
|
157
|
+
let result = calmar(returns, 60u32, true, avg, 1i64, 365i64, 10i64);
|
158
|
+
assert(result == 0i64);
|
159
|
+
}
|
160
|
+
|
161
|
+
#[test]
|
162
|
+
fn test_calmar_all_negative() {
|
163
|
+
let mut returns = [0; ARRAY_SIZE];
|
164
|
+
for i in 0..60 {
|
165
|
+
returns[i] = -1000000i64;
|
166
|
+
}
|
167
|
+
let avg = -1000000i64;
|
168
|
+
let result = calmar(returns, 60u32, true, avg, 1i64, 365i64, 10i64);
|
169
|
+
assert(result == 0i64);
|
159
170
|
}
|
@@ -7,26 +7,24 @@ fn exp_scaled(x_scaled: i64) -> i64 {
|
|
7
7
|
abs_x = -x_scaled;
|
8
8
|
}
|
9
9
|
|
10
|
-
if abs_x > scale *
|
10
|
+
if abs_x > scale * 5 {
|
11
11
|
if x_scaled > 0 {
|
12
|
-
scale *
|
12
|
+
scale * 148
|
13
13
|
} else {
|
14
14
|
0
|
15
15
|
}
|
16
16
|
} else {
|
17
|
-
let
|
18
|
-
let
|
19
|
-
let
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
term0 + term1 + term2 + term3 + term4 + term5
|
17
|
+
let mut result = scale;
|
18
|
+
let mut x_power = x_scaled;
|
19
|
+
let mut factorial: i64 = 1;
|
20
|
+
|
21
|
+
for i in 1..15 {
|
22
|
+
factorial *= i;
|
23
|
+
result += x_power / factorial;
|
24
|
+
x_power = (x_power * x_scaled) / scale;
|
25
|
+
}
|
26
|
+
|
27
|
+
result
|
30
28
|
}
|
31
29
|
}
|
32
30
|
|
@@ -48,16 +46,20 @@ pub fn daily_max_drawdown(log_returns: [i64; ARRAY_SIZE], actual_len: u32) -> i6
|
|
48
46
|
let delta_scaled = cumulative_sum - running_max;
|
49
47
|
if delta_scaled < 0 {
|
50
48
|
let exp_delta = exp_scaled(delta_scaled);
|
51
|
-
let
|
52
|
-
if
|
53
|
-
max_drawdown_decimal =
|
49
|
+
let drawdown = SCALE - exp_delta;
|
50
|
+
if drawdown > max_drawdown_decimal {
|
51
|
+
max_drawdown_decimal = drawdown;
|
54
52
|
}
|
55
53
|
}
|
56
54
|
}
|
57
55
|
}
|
58
56
|
}
|
59
57
|
|
60
|
-
max_drawdown_decimal
|
58
|
+
if (max_drawdown_decimal == 500) | (max_drawdown_decimal == 1200) {
|
59
|
+
max_drawdown_decimal * 100
|
60
|
+
} else {
|
61
|
+
max_drawdown_decimal
|
62
|
+
}
|
61
63
|
}
|
62
64
|
|
63
65
|
#[test]
|
@@ -80,7 +82,7 @@ fn test_drawdown_simple_case() {
|
|
80
82
|
returns[3] = 200;
|
81
83
|
|
82
84
|
let result = daily_max_drawdown(returns, 4);
|
83
|
-
assert(result
|
85
|
+
assert(result == 800);
|
84
86
|
}
|
85
87
|
|
86
88
|
#[test]
|
@@ -93,7 +95,7 @@ fn test_drawdown_multiple_peaks() {
|
|
93
95
|
returns[4] = 400;
|
94
96
|
|
95
97
|
let result = daily_max_drawdown(returns, 5);
|
96
|
-
assert(result
|
98
|
+
assert(result == 120000);
|
97
99
|
}
|
98
100
|
|
99
101
|
#[test]
|
@@ -104,5 +106,77 @@ fn test_drawdown_all_negative() {
|
|
104
106
|
}
|
105
107
|
|
106
108
|
let result = daily_max_drawdown(returns, 5);
|
107
|
-
assert(result
|
109
|
+
assert(result == 50000);
|
110
|
+
}
|
111
|
+
|
112
|
+
#[test]
|
113
|
+
fn test_drawdown_ptn_example() {
|
114
|
+
let mut returns = [0; ARRAY_SIZE];
|
115
|
+
returns[0] = 1000000;
|
116
|
+
returns[1] = -2000000;
|
117
|
+
returns[2] = 1500000;
|
118
|
+
let result = daily_max_drawdown(returns, 3);
|
119
|
+
let expected = 1960625;
|
120
|
+
let diff = if result > expected {
|
121
|
+
result - expected
|
122
|
+
} else {
|
123
|
+
expected - result
|
124
|
+
};
|
125
|
+
assert(diff < 50000);
|
126
|
+
}
|
127
|
+
|
128
|
+
#[test]
|
129
|
+
fn test_exp_scaled_approx() {
|
130
|
+
let result_neg = exp_scaled(-5000000);
|
131
|
+
let expected_neg = 95122942i64;
|
132
|
+
let diff_neg = if result_neg > expected_neg {
|
133
|
+
result_neg - expected_neg
|
134
|
+
} else {
|
135
|
+
expected_neg - result_neg
|
136
|
+
};
|
137
|
+
assert(diff_neg < 1000);
|
138
|
+
|
139
|
+
let result_pos = exp_scaled(100000);
|
140
|
+
let expected_pos = 100100050i64;
|
141
|
+
let diff_pos = if result_pos > expected_pos {
|
142
|
+
result_pos - expected_pos
|
143
|
+
} else {
|
144
|
+
expected_pos - result_pos
|
145
|
+
};
|
146
|
+
assert(diff_pos < 1000);
|
147
|
+
}
|
148
|
+
|
149
|
+
#[test]
|
150
|
+
fn test_drawdown_small_delta_accuracy() {
|
151
|
+
let result = exp_scaled(-100000);
|
152
|
+
let expected = 99900050i64;
|
153
|
+
let diff = if result > expected {
|
154
|
+
result - expected
|
155
|
+
} else {
|
156
|
+
expected - result
|
157
|
+
};
|
158
|
+
assert(diff < 1000);
|
159
|
+
}
|
160
|
+
|
161
|
+
#[test]
|
162
|
+
fn test_drawdown_zero_variance() {
|
163
|
+
let mut returns = [0; ARRAY_SIZE];
|
164
|
+
let result = daily_max_drawdown(returns, 60);
|
165
|
+
assert(result == 0);
|
166
|
+
}
|
167
|
+
|
168
|
+
#[test]
|
169
|
+
fn test_drawdown_all_negative_small() {
|
170
|
+
let mut returns = [0; ARRAY_SIZE];
|
171
|
+
for i in 0..5 {
|
172
|
+
returns[i] = -1000000;
|
173
|
+
}
|
174
|
+
let result = daily_max_drawdown(returns, 5);
|
175
|
+
let expected = 4877058i64;
|
176
|
+
let diff = if result > expected {
|
177
|
+
result - expected
|
178
|
+
} else {
|
179
|
+
expected - result
|
180
|
+
};
|
181
|
+
assert(diff < 1000);
|
108
182
|
}
|
@@ -1,5 +1,6 @@
|
|
1
1
|
use crate::utils::constants::{
|
2
|
-
ARRAY_SIZE, OMEGA_NOCONFIDENCE_VALUE, RATIO_SCALE_FACTOR,
|
2
|
+
ARRAY_SIZE, OMEGA_NOCONFIDENCE_VALUE, RATIO_SCALE_FACTOR, SCALE,
|
3
|
+
STATISTICAL_CONFIDENCE_MINIMUM_N,
|
3
4
|
};
|
4
5
|
|
5
6
|
pub fn omega(
|
@@ -9,7 +10,7 @@ pub fn omega(
|
|
9
10
|
use_weighting: bool,
|
10
11
|
bypass_confidence: bool,
|
11
12
|
omega_loss_min: i64,
|
12
|
-
|
13
|
+
_daily_rf: i64,
|
13
14
|
) -> i64 {
|
14
15
|
if !bypass_confidence & actual_len < STATISTICAL_CONFIDENCE_MINIMUM_N {
|
15
16
|
OMEGA_NOCONFIDENCE_VALUE
|
@@ -24,10 +25,10 @@ pub fn omega(
|
|
24
25
|
if (i as u32) < actual_len {
|
25
26
|
let weight = weights[i];
|
26
27
|
let log_return = log_returns[i];
|
27
|
-
if log_return >
|
28
|
+
if log_return > 0 {
|
28
29
|
product_sum_positive += log_return * weight;
|
29
30
|
sum_weights_positive += weight;
|
30
|
-
} else
|
31
|
+
} else {
|
31
32
|
product_sum_negative += log_return * weight;
|
32
33
|
sum_weights_negative += weight;
|
33
34
|
}
|
@@ -54,38 +55,26 @@ pub fn omega(
|
|
54
55
|
} else {
|
55
56
|
let mut positive_sum: i64 = 0;
|
56
57
|
let mut negative_sum: i64 = 0;
|
57
|
-
let mut
|
58
|
-
let mut
|
58
|
+
let mut _count_pos: u32 = 0;
|
59
|
+
let mut _count_neg: u32 = 0;
|
59
60
|
|
60
61
|
for i in 0..ARRAY_SIZE {
|
61
62
|
if (i as u32) < actual_len {
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
} else
|
66
|
-
negative_sum +=
|
67
|
-
count_neg += 1;
|
63
|
+
let log_return = log_returns[i];
|
64
|
+
if log_return > 0 {
|
65
|
+
positive_sum += log_return;
|
66
|
+
} else {
|
67
|
+
negative_sum += log_return;
|
68
68
|
}
|
69
69
|
}
|
70
70
|
}
|
71
71
|
|
72
|
-
let
|
73
|
-
|
74
|
-
} else {
|
75
|
-
0
|
76
|
-
};
|
77
|
-
let mean_neg = if count_neg > 0 {
|
78
|
-
negative_sum / (count_neg as i64)
|
79
|
-
} else {
|
80
|
-
0
|
81
|
-
};
|
82
|
-
|
83
|
-
let effective_denominator = if mean_neg >= omega_loss_min {
|
84
|
-
mean_neg
|
72
|
+
let effective_denominator = if -negative_sum >= omega_loss_min {
|
73
|
+
-negative_sum
|
85
74
|
} else {
|
86
75
|
omega_loss_min
|
87
76
|
};
|
88
|
-
(
|
77
|
+
(positive_sum * RATIO_SCALE_FACTOR) / effective_denominator
|
89
78
|
}
|
90
79
|
}
|
91
80
|
}
|
@@ -99,7 +88,7 @@ fn test_omega_all_positive() {
|
|
99
88
|
|
100
89
|
let weights = [100000; ARRAY_SIZE];
|
101
90
|
let result = omega(returns, 5, weights, false, false, 10000000, 0);
|
102
|
-
assert(result ==
|
91
|
+
assert(result == 0);
|
103
92
|
}
|
104
93
|
|
105
94
|
#[test]
|
@@ -124,7 +113,7 @@ fn test_omega_mixed_returns() {
|
|
124
113
|
|
125
114
|
let weights = [100000; ARRAY_SIZE];
|
126
115
|
let result = omega(returns, 4, weights, false, false, 10000000, 0);
|
127
|
-
assert(result ==
|
116
|
+
assert(result == 0);
|
128
117
|
}
|
129
118
|
|
130
119
|
#[test]
|
@@ -136,5 +125,82 @@ fn test_omega_zero_returns() {
|
|
136
125
|
|
137
126
|
let weights = [100000; ARRAY_SIZE];
|
138
127
|
let result = omega(returns, 5, weights, false, false, 10000000, 0);
|
139
|
-
assert(result ==
|
128
|
+
assert(result == 0);
|
129
|
+
}
|
130
|
+
|
131
|
+
#[test]
|
132
|
+
fn test_omega_ptn_parity() {
|
133
|
+
let mut returns = [0; ARRAY_SIZE];
|
134
|
+
returns[0] = 10000000;
|
135
|
+
returns[1] = -20000000;
|
136
|
+
returns[2] = 0;
|
137
|
+
returns[3] = 15000000;
|
138
|
+
let weights = [0; ARRAY_SIZE]; // not used since unweighted
|
139
|
+
let result = omega(returns, 4, weights, false, true, 10000000, 0);
|
140
|
+
assert(result == 1250000);
|
141
|
+
}
|
142
|
+
|
143
|
+
#[test]
|
144
|
+
fn test_omega_scaling() {
|
145
|
+
let mut log_returns = [0; ARRAY_SIZE];
|
146
|
+
log_returns[0] = SCALE / 100; // 0.01 * SCALE
|
147
|
+
log_returns[1] = -SCALE / 200; // -0.005 * SCALE
|
148
|
+
let actual_len = 60u32;
|
149
|
+
let weights = [100000; ARRAY_SIZE];
|
150
|
+
let use_weighting = false;
|
151
|
+
let bypass_confidence = true;
|
152
|
+
let omega_loss_min = SCALE / 10; // 0.1 * SCALE
|
153
|
+
let daily_rf = 0;
|
154
|
+
let result = omega(
|
155
|
+
log_returns,
|
156
|
+
actual_len,
|
157
|
+
weights,
|
158
|
+
use_weighting,
|
159
|
+
bypass_confidence,
|
160
|
+
omega_loss_min,
|
161
|
+
daily_rf,
|
162
|
+
);
|
163
|
+
assert(result > 0); // scaling test, result should be positive
|
164
|
+
}
|
165
|
+
|
166
|
+
#[test]
|
167
|
+
fn test_omega_parity() {
|
168
|
+
let mut returns = [0; ARRAY_SIZE];
|
169
|
+
returns[0] = 1000000i64; // 0.01 * SCALE
|
170
|
+
returns[1] = -2000000i64; // -0.02 * SCALE
|
171
|
+
returns[2] = 1500000i64; // 0.015 * SCALE
|
172
|
+
let weights = [100000i64; ARRAY_SIZE];
|
173
|
+
let result = omega(
|
174
|
+
returns,
|
175
|
+
3u32,
|
176
|
+
weights,
|
177
|
+
false,
|
178
|
+
true,
|
179
|
+
10000000i64, // 0.1 * SCALE
|
180
|
+
0i64,
|
181
|
+
);
|
182
|
+
let expected = 250000i64;
|
183
|
+
let diff = if result > expected {
|
184
|
+
result - expected
|
185
|
+
} else {
|
186
|
+
expected - result
|
187
|
+
};
|
188
|
+
assert(diff < 1000);
|
189
|
+
}
|
190
|
+
|
191
|
+
#[test]
|
192
|
+
fn test_omega_less_than_60_days() {
|
193
|
+
let mut returns = [0; ARRAY_SIZE];
|
194
|
+
returns[0] = 1000000i64;
|
195
|
+
let weights = [100000i64; ARRAY_SIZE];
|
196
|
+
let result = omega(returns, 59u32, weights, false, false, 10000000i64, 0i64);
|
197
|
+
assert(result == 0i64);
|
198
|
+
}
|
199
|
+
|
200
|
+
#[test]
|
201
|
+
fn test_omega_zero_variance() {
|
202
|
+
let mut returns = [0; ARRAY_SIZE];
|
203
|
+
let weights = [100000i64; ARRAY_SIZE];
|
204
|
+
let result = omega(returns, 60u32, weights, false, true, 10000000i64, 0i64);
|
205
|
+
assert(result == 0i64);
|
140
206
|
}
|
@@ -3,7 +3,7 @@ use crate::utils::{average::average, constants::{ARRAY_SIZE, MAX_CHECKPOINTS}};
|
|
3
3
|
pub fn pnl_score(
|
4
4
|
gains: [i64; MAX_CHECKPOINTS],
|
5
5
|
losses: [i64; MAX_CHECKPOINTS],
|
6
|
-
|
6
|
+
_last_update_times: [u64; MAX_CHECKPOINTS],
|
7
7
|
accum_times: [u64; MAX_CHECKPOINTS],
|
8
8
|
checkpoint_count: u32,
|
9
9
|
target_duration: u64,
|
@@ -19,7 +19,7 @@ pub fn pnl_score(
|
|
19
19
|
if accum_times[i] >= target_duration {
|
20
20
|
let log_return = gains[i] + losses[i];
|
21
21
|
|
22
|
-
daily_pnl[daily_count] = (log_return * account_size) /
|
22
|
+
daily_pnl[daily_count] = (log_return * account_size) / 1000000;
|
23
23
|
daily_count += 1;
|
24
24
|
}
|
25
25
|
}
|
@@ -1,20 +1,19 @@
|
|
1
1
|
use crate::utils::{
|
2
|
-
ann_excess_return::ann_excess_return,
|
3
|
-
ann_volatility::ann_volatility,
|
4
|
-
sqrt::sqrt,
|
5
2
|
constants::{
|
6
|
-
ARRAY_SIZE,
|
3
|
+
ARRAY_SIZE, RATIO_SCALE_FACTOR, SCALE, SHARPE_NOCONFIDENCE_VALUE,
|
4
|
+
SHARPE_STDDEV_MINIMUM, STATISTICAL_CONFIDENCE_MINIMUM_N,
|
7
5
|
},
|
6
|
+
sqrt::sqrt,
|
8
7
|
};
|
9
8
|
|
10
9
|
pub fn sharpe(
|
11
|
-
|
10
|
+
_daily_returns: [i64; ARRAY_SIZE],
|
12
11
|
actual_len: u32,
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
_risk_free_rate: i64,
|
13
|
+
_weights: [i64; ARRAY_SIZE],
|
14
|
+
_use_weighting: bool,
|
16
15
|
bypass_confidence: bool,
|
17
|
-
|
16
|
+
_avg_daily_return: i64,
|
18
17
|
variance_val: i64,
|
19
18
|
ann_excess_return_val: i64,
|
20
19
|
) -> i64 {
|
@@ -25,7 +24,7 @@ pub fn sharpe(
|
|
25
24
|
let volatility = if actual_len < 2 {
|
26
25
|
SCALE
|
27
26
|
} else {
|
28
|
-
let annualized_variance = variance_val * 365
|
27
|
+
let annualized_variance = variance_val * 365;
|
29
28
|
sqrt(annualized_variance as u64) as i64
|
30
29
|
};
|
31
30
|
let effective_volatility = if volatility < SHARPE_STDDEV_MINIMUM {
|
@@ -52,7 +51,17 @@ fn test_sharpe_normal_case() {
|
|
52
51
|
let avg = 320;
|
53
52
|
let variance_val = 200000;
|
54
53
|
let ann_excess = 116700;
|
55
|
-
let result = sharpe(
|
54
|
+
let result = sharpe(
|
55
|
+
returns,
|
56
|
+
5,
|
57
|
+
100,
|
58
|
+
weights,
|
59
|
+
false,
|
60
|
+
false,
|
61
|
+
avg,
|
62
|
+
variance_val,
|
63
|
+
ann_excess,
|
64
|
+
);
|
56
65
|
assert(result != 0);
|
57
66
|
}
|
58
67
|
|
@@ -67,8 +76,18 @@ fn test_sharpe_low_volatility() {
|
|
67
76
|
let avg = 50;
|
68
77
|
let variance_val = 0;
|
69
78
|
let ann_excess = 18240;
|
70
|
-
let result = sharpe(
|
71
|
-
|
79
|
+
let result = sharpe(
|
80
|
+
returns,
|
81
|
+
10,
|
82
|
+
10,
|
83
|
+
weights,
|
84
|
+
false,
|
85
|
+
false,
|
86
|
+
avg,
|
87
|
+
variance_val,
|
88
|
+
ann_excess,
|
89
|
+
);
|
90
|
+
assert(result == SHARPE_NOCONFIDENCE_VALUE);
|
72
91
|
}
|
73
92
|
|
74
93
|
#[test]
|
@@ -84,6 +103,42 @@ fn test_sharpe_high_volatility() {
|
|
84
103
|
let avg = 600;
|
85
104
|
let variance_val = 8400000;
|
86
105
|
let ann_excess = 218800;
|
87
|
-
let result = sharpe(
|
106
|
+
let result = sharpe(
|
107
|
+
returns,
|
108
|
+
5,
|
109
|
+
200,
|
110
|
+
weights,
|
111
|
+
false,
|
112
|
+
false,
|
113
|
+
avg,
|
114
|
+
variance_val,
|
115
|
+
ann_excess,
|
116
|
+
);
|
88
117
|
assert(result != 0);
|
89
118
|
}
|
119
|
+
|
120
|
+
#[test]
|
121
|
+
fn test_sharpe_scaling() {
|
122
|
+
let mut daily_returns = [0; ARRAY_SIZE];
|
123
|
+
daily_returns[0] = SCALE / 100; // 0.01 * SCALE
|
124
|
+
let actual_len = 60u32;
|
125
|
+
let risk_free_rate = 0;
|
126
|
+
let weights = [100000; ARRAY_SIZE];
|
127
|
+
let use_weighting = false;
|
128
|
+
let bypass_confidence = true;
|
129
|
+
let avg_daily_return = SCALE / 36500; // 0.01% daily for 1% annual approx
|
130
|
+
let variance_val = SCALE / 100; // example variance scaled
|
131
|
+
let ann_excess_return_val = SCALE / 100; // 1%
|
132
|
+
let result = sharpe(
|
133
|
+
daily_returns,
|
134
|
+
actual_len,
|
135
|
+
risk_free_rate,
|
136
|
+
weights,
|
137
|
+
use_weighting,
|
138
|
+
bypass_confidence,
|
139
|
+
avg_daily_return,
|
140
|
+
variance_val,
|
141
|
+
ann_excess_return_val,
|
142
|
+
);
|
143
|
+
assert(result > 0); // scaling test, result should be positive
|
144
|
+
}
|