sqa 0.0.32 → 0.0.38
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +154 -1
- data/README.md +4 -0
- data/Rakefile +52 -10
- data/docs/advanced/index.md +1 -13
- data/docs/api/index.md +547 -61
- data/docs/api-reference/alphavantageapi.md +1057 -0
- data/docs/api-reference/apierror.md +31 -0
- data/docs/api-reference/index.md +221 -0
- data/docs/api-reference/notimplemented.md +27 -0
- data/docs/api-reference/sqa.md +267 -0
- data/docs/api-reference/sqa_backtest.md +171 -0
- data/docs/api-reference/sqa_backtest_results.md +530 -0
- data/docs/api-reference/sqa_badparametererror.md +13 -0
- data/docs/api-reference/sqa_config.md +538 -0
- data/docs/api-reference/sqa_configurationerror.md +13 -0
- data/docs/api-reference/sqa_datafetcherror.md +56 -0
- data/docs/api-reference/sqa_dataframe.md +779 -0
- data/docs/api-reference/sqa_dataframe_alphavantage.md +30 -0
- data/docs/api-reference/sqa_dataframe_data.md +325 -0
- data/docs/api-reference/sqa_dataframe_yahoofinance.md +25 -0
- data/docs/api-reference/sqa_ensemble.md +413 -0
- data/docs/api-reference/sqa_fpop.md +211 -0
- data/docs/api-reference/sqa_geneticprogram.md +325 -0
- data/docs/api-reference/sqa_geneticprogram_individual.md +114 -0
- data/docs/api-reference/sqa_marketregime.md +212 -0
- data/docs/api-reference/sqa_multitimeframe.md +227 -0
- data/docs/api-reference/sqa_patternmatcher.md +195 -0
- data/docs/api-reference/sqa_pluginmanager.md +55 -0
- data/docs/api-reference/sqa_portfolio.md +512 -0
- data/docs/api-reference/sqa_portfolio_position.md +220 -0
- data/docs/api-reference/sqa_portfolio_trade.md +332 -0
- data/docs/api-reference/sqa_portfoliooptimizer.md +248 -0
- data/docs/api-reference/sqa_riskmanager.md +388 -0
- data/docs/api-reference/sqa_seasonalanalyzer.md +121 -0
- data/docs/api-reference/sqa_sectoranalyzer.md +163 -0
- data/docs/api-reference/sqa_stock.md +661 -0
- data/docs/api-reference/sqa_strategy.md +178 -0
- data/docs/api-reference/sqa_strategy_bollingerbands.md +26 -0
- data/docs/api-reference/sqa_strategy_common.md +29 -0
- data/docs/api-reference/sqa_strategy_consensus.md +129 -0
- data/docs/api-reference/sqa_strategy_ema.md +41 -0
- data/docs/api-reference/sqa_strategy_kbs.md +154 -0
- data/docs/api-reference/sqa_strategy_macd.md +26 -0
- data/docs/api-reference/sqa_strategy_mp.md +41 -0
- data/docs/api-reference/sqa_strategy_mr.md +41 -0
- data/docs/api-reference/sqa_strategy_random.md +41 -0
- data/docs/api-reference/sqa_strategy_rsi.md +41 -0
- data/docs/api-reference/sqa_strategy_sma.md +41 -0
- data/docs/api-reference/sqa_strategy_stochastic.md +26 -0
- data/docs/api-reference/sqa_strategy_volumebreakout.md +26 -0
- data/docs/api-reference/sqa_strategygenerator.md +298 -0
- data/docs/api-reference/sqa_strategygenerator_pattern.md +264 -0
- data/docs/api-reference/sqa_strategygenerator_patterncontext.md +326 -0
- data/docs/api-reference/sqa_strategygenerator_profitablepoint.md +424 -0
- data/docs/api-reference/sqa_stream.md +256 -0
- data/docs/api-reference/sqa_ticker.md +175 -0
- data/docs/api-reference/string.md +135 -0
- data/docs/assets/images/advanced-workflow.svg +89 -0
- data/docs/assets/images/architecture.svg +107 -0
- data/docs/assets/images/data-flow.svg +138 -0
- data/docs/assets/images/getting-started-workflow.svg +88 -0
- data/docs/assets/images/strategy-flow.svg +78 -0
- data/docs/assets/images/system-architecture.svg +150 -0
- data/docs/concepts/index.md +292 -19
- data/docs/file_formats.md +250 -0
- data/docs/getting-started/index.md +1 -14
- data/docs/index.md +26 -23
- data/docs/llms.txt +109 -0
- data/docs/strategies/kbs.md +15 -14
- data/docs/strategy.md +381 -3
- data/docs/terms_of_use.md +1 -1
- data/examples/README.md +10 -0
- data/lib/api/alpha_vantage_api.rb +3 -7
- data/lib/sqa/backtest.rb +32 -0
- data/lib/sqa/config.rb +109 -28
- data/lib/sqa/data_frame/data.rb +13 -1
- data/lib/sqa/data_frame.rb +193 -26
- data/lib/sqa/errors.rb +79 -17
- data/lib/sqa/init.rb +70 -15
- data/lib/sqa/pattern_matcher.rb +4 -4
- data/lib/sqa/portfolio.rb +55 -1
- data/lib/sqa/sector_analyzer.rb +3 -11
- data/lib/sqa/stock.rb +180 -15
- data/lib/sqa/strategy.rb +62 -4
- data/lib/sqa/ticker.rb +106 -48
- data/lib/sqa/version.rb +1 -1
- data/lib/sqa.rb +4 -4
- data/mkdocs.yml +69 -81
- metadata +89 -21
- data/docs/README.md +0 -43
- data/examples/sinatra_app/Gemfile +0 -42
- data/examples/sinatra_app/Gemfile.lock +0 -268
- data/examples/sinatra_app/QUICKSTART.md +0 -169
- data/examples/sinatra_app/README.md +0 -471
- data/examples/sinatra_app/RUNNING_WITHOUT_TALIB.md +0 -90
- data/examples/sinatra_app/TROUBLESHOOTING.md +0 -95
- data/examples/sinatra_app/app.rb +0 -404
- data/examples/sinatra_app/config.ru +0 -5
- data/examples/sinatra_app/public/css/style.css +0 -723
- data/examples/sinatra_app/public/debug_macd.html +0 -82
- data/examples/sinatra_app/public/js/app.js +0 -107
- data/examples/sinatra_app/start.sh +0 -53
- data/examples/sinatra_app/views/analyze.erb +0 -306
- data/examples/sinatra_app/views/backtest.erb +0 -325
- data/examples/sinatra_app/views/dashboard.erb +0 -831
- data/examples/sinatra_app/views/error.erb +0 -58
- data/examples/sinatra_app/views/index.erb +0 -118
- data/examples/sinatra_app/views/layout.erb +0 -61
- data/examples/sinatra_app/views/portfolio.erb +0 -43
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# 📦 SQA::RiskManager
|
|
2
|
+
|
|
3
|
+
!!! note "Description"
|
|
4
|
+
RiskManager - Comprehensive risk management and position sizing
|
|
5
|
+
|
|
6
|
+
Provides methods for:
|
|
7
|
+
- Value at Risk (VaR): Historical, Parametric, Monte Carlo
|
|
8
|
+
- Conditional VaR (CVaR / Expected Shortfall)
|
|
9
|
+
- Position sizing: Kelly Criterion, Fixed Fractional, Percent Volatility
|
|
10
|
+
- Risk metrics: Sharpe, Sortino, Calmar, Maximum Drawdown
|
|
11
|
+
- Stop loss calculations
|
|
12
|
+
|
|
13
|
+
!!! abstract "Source Information"
|
|
14
|
+
**Defined in:** [`lib/sqa/risk_manager.rb:29`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L29)
|
|
15
|
+
|
|
16
|
+
**Inherits from:** `Object`
|
|
17
|
+
|
|
18
|
+
## 🏭 Class Methods
|
|
19
|
+
|
|
20
|
+
### `.var(returns, confidence: = 0.95, method: = :historical, simulations: = 10_000)`
|
|
21
|
+
|
|
22
|
+
Calculate Value at Risk (VaR) using historical method
|
|
23
|
+
|
|
24
|
+
VaR represents the maximum expected loss over a given time period
|
|
25
|
+
at a specified confidence level.
|
|
26
|
+
|
|
27
|
+
!!! info "Parameters"
|
|
28
|
+
|
|
29
|
+
| Name | Type | Description |
|
|
30
|
+
|------|------|-------------|
|
|
31
|
+
| `returns` | `Array<Float>` | Array of period returns (e.g., daily returns) |
|
|
32
|
+
| `confidence` | `Float` | Confidence level (default: 0.95 for 95%) |
|
|
33
|
+
| `method` | `Symbol` | Method to use (:historical, :parametric, :monte_carlo) |
|
|
34
|
+
| `simulations` | `Integer` | Number of Monte Carlo simulations (if method is :monte_carlo) |
|
|
35
|
+
!!! success "Returns"
|
|
36
|
+
|
|
37
|
+
**Type:** `Float`
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
Value at Risk as a percentage
|
|
42
|
+
!!! example "Usage Examples"
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
returns = [0.01, -0.02, 0.015, -0.01, 0.005]
|
|
46
|
+
var = SQA::RiskManager.var(returns, confidence: 0.95)
|
|
47
|
+
# => -0.02 (2% maximum expected loss at 95% confidence)
|
|
48
|
+
```
|
|
49
|
+
??? info "Source Location"
|
|
50
|
+
[`lib/sqa/risk_manager.rb:48`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L48)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
### `.cvar(returns, confidence: = 0.95)`
|
|
55
|
+
|
|
56
|
+
Calculate Conditional Value at Risk (CVaR / Expected Shortfall)
|
|
57
|
+
|
|
58
|
+
CVaR is the expected loss given that the loss exceeds the VaR threshold.
|
|
59
|
+
It provides a more conservative risk measure than VaR.
|
|
60
|
+
|
|
61
|
+
!!! info "Parameters"
|
|
62
|
+
|
|
63
|
+
| Name | Type | Description |
|
|
64
|
+
|------|------|-------------|
|
|
65
|
+
| `returns` | `Array<Float>` | Array of period returns |
|
|
66
|
+
| `confidence` | `Float` | Confidence level (default: 0.95) |
|
|
67
|
+
!!! success "Returns"
|
|
68
|
+
|
|
69
|
+
**Type:** `Float`
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
CVaR as a percentage
|
|
74
|
+
!!! example "Usage Examples"
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
cvar = SQA::RiskManager.cvar(returns, confidence: 0.95)
|
|
78
|
+
# => -0.025 (2.5% expected loss in worst 5% of cases)
|
|
79
|
+
```
|
|
80
|
+
??? info "Source Location"
|
|
81
|
+
[`lib/sqa/risk_manager.rb:77`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L77)
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
### `.kelly_criterion(win_rate:, avg_win:, avg_loss:, capital:, max_fraction: = 0.25)`
|
|
86
|
+
|
|
87
|
+
Calculate position size using Kelly Criterion
|
|
88
|
+
|
|
89
|
+
Kelly Criterion calculates the optimal fraction of capital to risk
|
|
90
|
+
based on win rate and win/loss ratio.
|
|
91
|
+
|
|
92
|
+
Formula: f = (p * b - q) / b
|
|
93
|
+
where:
|
|
94
|
+
f = fraction of capital to bet
|
|
95
|
+
p = probability of winning
|
|
96
|
+
q = probability of losing (1 - p)
|
|
97
|
+
b = win/loss ratio (avg_win / avg_loss)
|
|
98
|
+
|
|
99
|
+
!!! info "Parameters"
|
|
100
|
+
|
|
101
|
+
| Name | Type | Description |
|
|
102
|
+
|------|------|-------------|
|
|
103
|
+
| `win_rate` | `Float` | Win rate (0.0 to 1.0) |
|
|
104
|
+
| `avg_win` | `Float` | Average win size (as percentage) |
|
|
105
|
+
| `avg_loss` | `Float` | Average loss size (as percentage) |
|
|
106
|
+
| `capital` | `Float` | Total capital available |
|
|
107
|
+
| `max_fraction` | `Float` | Maximum fraction to risk (default: 0.25 for 25%) |
|
|
108
|
+
!!! success "Returns"
|
|
109
|
+
|
|
110
|
+
**Type:** `Float`
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
Dollar amount to risk
|
|
115
|
+
!!! example "Usage Examples"
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
position = SQA::RiskManager.kelly_criterion(
|
|
119
|
+
win_rate: 0.60,
|
|
120
|
+
avg_win: 0.10,
|
|
121
|
+
avg_loss: 0.05,
|
|
122
|
+
capital: 10_000,
|
|
123
|
+
max_fraction: 0.25
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
??? info "Source Location"
|
|
127
|
+
[`lib/sqa/risk_manager.rb:116`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L116)
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### `.fixed_fractional(capital:, risk_fraction: = 0.02)`
|
|
132
|
+
|
|
133
|
+
Calculate position size using Fixed Fractional method
|
|
134
|
+
|
|
135
|
+
Risk a fixed percentage of capital on each trade.
|
|
136
|
+
Simple and conservative approach.
|
|
137
|
+
|
|
138
|
+
!!! info "Parameters"
|
|
139
|
+
|
|
140
|
+
| Name | Type | Description |
|
|
141
|
+
|------|------|-------------|
|
|
142
|
+
| `capital` | `Float` | Total capital |
|
|
143
|
+
| `risk_fraction` | `Float` | Fraction to risk (e.g., 0.02 for 2%) |
|
|
144
|
+
!!! success "Returns"
|
|
145
|
+
|
|
146
|
+
**Type:** `Float`
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
Dollar amount to risk
|
|
151
|
+
!!! example "Usage Examples"
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
position = SQA::RiskManager.fixed_fractional(capital: 10_000, risk_fraction: 0.02)
|
|
155
|
+
# => 200.0 (risk $200 per trade)
|
|
156
|
+
```
|
|
157
|
+
??? info "Source Location"
|
|
158
|
+
[`lib/sqa/risk_manager.rb:146`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L146)
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### `.percent_volatility(capital:, returns:, target_volatility: = 0.15, current_price:)`
|
|
163
|
+
|
|
164
|
+
Calculate position size using Percent Volatility method
|
|
165
|
+
|
|
166
|
+
Adjust position size based on recent volatility.
|
|
167
|
+
Higher volatility = smaller position size.
|
|
168
|
+
|
|
169
|
+
!!! info "Parameters"
|
|
170
|
+
|
|
171
|
+
| Name | Type | Description |
|
|
172
|
+
|------|------|-------------|
|
|
173
|
+
| `capital` | `Float` | Total capital |
|
|
174
|
+
| `returns` | `Array<Float>` | Recent returns |
|
|
175
|
+
| `target_volatility` | `Float` | Target portfolio volatility (annualized) |
|
|
176
|
+
| `current_price` | `Float` | Current asset price |
|
|
177
|
+
!!! success "Returns"
|
|
178
|
+
|
|
179
|
+
**Type:** `Integer`
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
Number of shares to buy
|
|
184
|
+
!!! example "Usage Examples"
|
|
185
|
+
|
|
186
|
+
```ruby
|
|
187
|
+
shares = SQA::RiskManager.percent_volatility(
|
|
188
|
+
capital: 10_000,
|
|
189
|
+
returns: recent_returns,
|
|
190
|
+
target_volatility: 0.15,
|
|
191
|
+
current_price: 150.0
|
|
192
|
+
)
|
|
193
|
+
```
|
|
194
|
+
??? info "Source Location"
|
|
195
|
+
[`lib/sqa/risk_manager.rb:170`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L170)
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### `.atr_stop_loss(current_price:, atr:, multiplier: = 2.0, direction: = :long)`
|
|
200
|
+
|
|
201
|
+
Calculate stop loss price based on ATR (Average True Range)
|
|
202
|
+
|
|
203
|
+
!!! info "Parameters"
|
|
204
|
+
|
|
205
|
+
| Name | Type | Description |
|
|
206
|
+
|------|------|-------------|
|
|
207
|
+
| `current_price` | `Float` | Current asset price |
|
|
208
|
+
| `atr` | `Float` | Average True Range |
|
|
209
|
+
| `multiplier` | `Float` | ATR multiplier (default: 2.0) |
|
|
210
|
+
| `direction` | `Symbol` | :long or :short |
|
|
211
|
+
!!! success "Returns"
|
|
212
|
+
|
|
213
|
+
**Type:** `Float`
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
Stop loss price
|
|
218
|
+
!!! example "Usage Examples"
|
|
219
|
+
|
|
220
|
+
```ruby
|
|
221
|
+
stop = SQA::RiskManager.atr_stop_loss(
|
|
222
|
+
current_price: 150.0,
|
|
223
|
+
atr: 3.5,
|
|
224
|
+
multiplier: 2.0,
|
|
225
|
+
direction: :long
|
|
226
|
+
)
|
|
227
|
+
# => 143.0 (stop at current - 2*ATR)
|
|
228
|
+
```
|
|
229
|
+
??? info "Source Location"
|
|
230
|
+
[`lib/sqa/risk_manager.rb:204`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L204)
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
### `.max_drawdown(prices)`
|
|
235
|
+
|
|
236
|
+
Calculate maximum drawdown from price series
|
|
237
|
+
|
|
238
|
+
Drawdown is the peak-to-trough decline in portfolio value.
|
|
239
|
+
|
|
240
|
+
!!! info "Parameters"
|
|
241
|
+
|
|
242
|
+
| Name | Type | Description |
|
|
243
|
+
|------|------|-------------|
|
|
244
|
+
| `prices` | `Array<Float>` | Array of prices or portfolio values |
|
|
245
|
+
!!! success "Returns"
|
|
246
|
+
|
|
247
|
+
**Type:** `Hash`
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
{ max_drawdown: Float, peak_idx: Integer, trough_idx: Integer }
|
|
252
|
+
!!! example "Usage Examples"
|
|
253
|
+
|
|
254
|
+
```ruby
|
|
255
|
+
dd = SQA::RiskManager.max_drawdown([100, 110, 105, 95, 100])
|
|
256
|
+
# => { max_drawdown: -0.136, peak_idx: 1, trough_idx: 3 }
|
|
257
|
+
```
|
|
258
|
+
??? info "Source Location"
|
|
259
|
+
[`lib/sqa/risk_manager.rb:224`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L224)
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
### `.sharpe_ratio(returns, risk_free_rate: = 0.02, periods_per_year: = 252)`
|
|
264
|
+
|
|
265
|
+
Calculate Sharpe Ratio
|
|
266
|
+
|
|
267
|
+
Measures risk-adjusted return (excess return per unit of risk).
|
|
268
|
+
|
|
269
|
+
!!! info "Parameters"
|
|
270
|
+
|
|
271
|
+
| Name | Type | Description |
|
|
272
|
+
|------|------|-------------|
|
|
273
|
+
| `returns` | `Array<Float>` | Array of period returns |
|
|
274
|
+
| `risk_free_rate` | `Float` | Risk-free rate (annualized, default: 0.02) |
|
|
275
|
+
| `periods_per_year` | `Integer` | Number of periods per year (default: 252 for daily) |
|
|
276
|
+
!!! success "Returns"
|
|
277
|
+
|
|
278
|
+
**Type:** `Float`
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
Sharpe ratio
|
|
283
|
+
!!! example "Usage Examples"
|
|
284
|
+
|
|
285
|
+
```ruby
|
|
286
|
+
sharpe = SQA::RiskManager.sharpe_ratio(returns, risk_free_rate: 0.02)
|
|
287
|
+
```
|
|
288
|
+
??? info "Source Location"
|
|
289
|
+
[`lib/sqa/risk_manager.rb:269`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L269)
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
### `.sortino_ratio(returns, target_return: = 0.0, periods_per_year: = 252)`
|
|
294
|
+
|
|
295
|
+
Calculate Sortino Ratio
|
|
296
|
+
|
|
297
|
+
Like Sharpe ratio but only penalizes downside volatility.
|
|
298
|
+
|
|
299
|
+
!!! info "Parameters"
|
|
300
|
+
|
|
301
|
+
| Name | Type | Description |
|
|
302
|
+
|------|------|-------------|
|
|
303
|
+
| `returns` | `Array<Float>` | Array of period returns |
|
|
304
|
+
| `target_return` | `Float` | Target return (default: 0.0) |
|
|
305
|
+
| `periods_per_year` | `Integer` | Number of periods per year (default: 252) |
|
|
306
|
+
!!! success "Returns"
|
|
307
|
+
|
|
308
|
+
**Type:** `Float`
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
Sortino ratio
|
|
313
|
+
!!! example "Usage Examples"
|
|
314
|
+
|
|
315
|
+
```ruby
|
|
316
|
+
sortino = SQA::RiskManager.sortino_ratio(returns)
|
|
317
|
+
```
|
|
318
|
+
??? info "Source Location"
|
|
319
|
+
[`lib/sqa/risk_manager.rb:294`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L294)
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
### `.calmar_ratio(returns, periods_per_year: = 252)`
|
|
324
|
+
|
|
325
|
+
Calculate Calmar Ratio
|
|
326
|
+
|
|
327
|
+
Ratio of annualized return to maximum drawdown.
|
|
328
|
+
|
|
329
|
+
!!! info "Parameters"
|
|
330
|
+
|
|
331
|
+
| Name | Type | Description |
|
|
332
|
+
|------|------|-------------|
|
|
333
|
+
| `returns` | `Array<Float>` | Array of period returns |
|
|
334
|
+
| `periods_per_year` | `Integer` | Number of periods per year (default: 252) |
|
|
335
|
+
!!! success "Returns"
|
|
336
|
+
|
|
337
|
+
**Type:** `Float`
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
Calmar ratio
|
|
342
|
+
!!! example "Usage Examples"
|
|
343
|
+
|
|
344
|
+
```ruby
|
|
345
|
+
calmar = SQA::RiskManager.calmar_ratio(returns)
|
|
346
|
+
```
|
|
347
|
+
??? info "Source Location"
|
|
348
|
+
[`lib/sqa/risk_manager.rb:325`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L325)
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
### `.monte_carlo_simulation(initial_capital:, returns:, periods:, simulations: = 1000)`
|
|
353
|
+
|
|
354
|
+
Monte Carlo simulation for portfolio value
|
|
355
|
+
|
|
356
|
+
!!! info "Parameters"
|
|
357
|
+
|
|
358
|
+
| Name | Type | Description |
|
|
359
|
+
|------|------|-------------|
|
|
360
|
+
| `initial_capital` | `Float` | Starting capital |
|
|
361
|
+
| `returns` | `Array<Float>` | Historical returns to sample from |
|
|
362
|
+
| `periods` | `Integer` | Number of periods to simulate |
|
|
363
|
+
| `simulations` | `Integer` | Number of simulation paths |
|
|
364
|
+
!!! success "Returns"
|
|
365
|
+
|
|
366
|
+
**Type:** `Hash`
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
Simulation results with percentiles
|
|
371
|
+
!!! example "Usage Examples"
|
|
372
|
+
|
|
373
|
+
```ruby
|
|
374
|
+
results = SQA::RiskManager.monte_carlo_simulation(
|
|
375
|
+
initial_capital: 10_000,
|
|
376
|
+
returns: historical_returns,
|
|
377
|
+
periods: 252,
|
|
378
|
+
simulations: 1000
|
|
379
|
+
)
|
|
380
|
+
puts "95th percentile: $#{results[:percentile_95]}"
|
|
381
|
+
```
|
|
382
|
+
??? info "Source Location"
|
|
383
|
+
[`lib/sqa/risk_manager.rb:360`](https://github.com/madbomber/sqa/blob/main/lib/sqa/risk_manager.rb#L360)
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## 📝 Attributes
|
|
388
|
+
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# 🔧 SQA::SeasonalAnalyzer
|
|
2
|
+
|
|
3
|
+
!!! abstract "Source Information"
|
|
4
|
+
**Defined in:** [`lib/sqa/seasonal_analyzer.rb:18`](https://github.com/madbomber/sqa/blob/main/lib/sqa/seasonal_analyzer.rb#L18)
|
|
5
|
+
|
|
6
|
+
## 🏭 Class Methods
|
|
7
|
+
|
|
8
|
+
### `.analyze(stock)`
|
|
9
|
+
|
|
10
|
+
Analyze seasonal performance patterns
|
|
11
|
+
|
|
12
|
+
!!! info "Parameters"
|
|
13
|
+
|
|
14
|
+
| Name | Type | Description |
|
|
15
|
+
|------|------|-------------|
|
|
16
|
+
| `stock` | `SQA::Stock` | Stock to analyze |
|
|
17
|
+
!!! success "Returns"
|
|
18
|
+
|
|
19
|
+
**Type:** `Hash`
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
Seasonal performance metadata
|
|
24
|
+
|
|
25
|
+
??? info "Source Location"
|
|
26
|
+
[`lib/sqa/seasonal_analyzer.rb:25`](https://github.com/madbomber/sqa/blob/main/lib/sqa/seasonal_analyzer.rb#L25)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
### `.filter_by_months(stock, months)`
|
|
31
|
+
|
|
32
|
+
Filter data by calendar months
|
|
33
|
+
|
|
34
|
+
!!! info "Parameters"
|
|
35
|
+
|
|
36
|
+
| Name | Type | Description |
|
|
37
|
+
|------|------|-------------|
|
|
38
|
+
| `stock` | `SQA::Stock` | Stock to analyze |
|
|
39
|
+
| `months` | `Array<Integer>` | Months to include (1-12) |
|
|
40
|
+
!!! success "Returns"
|
|
41
|
+
|
|
42
|
+
**Type:** `Hash`
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
Filtered data
|
|
47
|
+
|
|
48
|
+
??? info "Source Location"
|
|
49
|
+
[`lib/sqa/seasonal_analyzer.rb:56`](https://github.com/madbomber/sqa/blob/main/lib/sqa/seasonal_analyzer.rb#L56)
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### `.filter_by_quarters(stock, quarters)`
|
|
54
|
+
|
|
55
|
+
Filter data by quarters
|
|
56
|
+
|
|
57
|
+
!!! info "Parameters"
|
|
58
|
+
|
|
59
|
+
| Name | Type | Description |
|
|
60
|
+
|------|------|-------------|
|
|
61
|
+
| `stock` | `SQA::Stock` | Stock to analyze |
|
|
62
|
+
| `quarters` | `Array<Integer>` | Quarters to include (1-4) |
|
|
63
|
+
!!! success "Returns"
|
|
64
|
+
|
|
65
|
+
**Type:** `Hash`
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
Filtered data
|
|
70
|
+
|
|
71
|
+
??? info "Source Location"
|
|
72
|
+
[`lib/sqa/seasonal_analyzer.rb:82`](https://github.com/madbomber/sqa/blob/main/lib/sqa/seasonal_analyzer.rb#L82)
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### `.detect_seasonality(monthly_returns)`
|
|
77
|
+
|
|
78
|
+
Detect if stock has seasonal pattern
|
|
79
|
+
|
|
80
|
+
!!! info "Parameters"
|
|
81
|
+
|
|
82
|
+
| Name | Type | Description |
|
|
83
|
+
|------|------|-------------|
|
|
84
|
+
| `monthly_returns` | `Hash` | Monthly return statistics |
|
|
85
|
+
!!! success "Returns"
|
|
86
|
+
|
|
87
|
+
**Type:** `Boolean`
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
True if significant seasonal pattern exists
|
|
92
|
+
|
|
93
|
+
??? info "Source Location"
|
|
94
|
+
[`lib/sqa/seasonal_analyzer.rb:99`](https://github.com/madbomber/sqa/blob/main/lib/sqa/seasonal_analyzer.rb#L99)
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### `.context_for_date(date)`
|
|
99
|
+
|
|
100
|
+
Get seasonal context for a specific date
|
|
101
|
+
|
|
102
|
+
!!! info "Parameters"
|
|
103
|
+
|
|
104
|
+
| Name | Type | Description |
|
|
105
|
+
|------|------|-------------|
|
|
106
|
+
| `date` | `Date` | Date to check |
|
|
107
|
+
!!! success "Returns"
|
|
108
|
+
|
|
109
|
+
**Type:** `Hash`
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
Seasonal context
|
|
114
|
+
|
|
115
|
+
??? info "Source Location"
|
|
116
|
+
[`lib/sqa/seasonal_analyzer.rb:116`](https://github.com/madbomber/sqa/blob/main/lib/sqa/seasonal_analyzer.rb#L116)
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 📝 Attributes
|
|
121
|
+
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# 📦 SQA::SectorAnalyzer
|
|
2
|
+
|
|
3
|
+
!!! abstract "Source Information"
|
|
4
|
+
**Defined in:** [`lib/sqa/sector_analyzer.rb:26`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L26)
|
|
5
|
+
|
|
6
|
+
**Inherits from:** `Object`
|
|
7
|
+
|
|
8
|
+
## 🔨 Instance Methods
|
|
9
|
+
|
|
10
|
+
### `#blackboards()`
|
|
11
|
+
|
|
12
|
+
Returns the value of attribute blackboards.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
??? info "Source Location"
|
|
18
|
+
[`lib/sqa/sector_analyzer.rb:40`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L40)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
### `#stocks_by_sector()`
|
|
23
|
+
|
|
24
|
+
Returns the value of attribute stocks_by_sector.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
??? info "Source Location"
|
|
30
|
+
[`lib/sqa/sector_analyzer.rb:40`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L40)
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
### `#initialize(db_dir: = '/tmp/sqa_sectors')`
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
!!! success "Returns"
|
|
38
|
+
|
|
39
|
+
**Type:** `SectorAnalyzer`
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
a new instance of SectorAnalyzer
|
|
44
|
+
|
|
45
|
+
??? info "Source Location"
|
|
46
|
+
[`lib/sqa/sector_analyzer.rb:42`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L42)
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
### `#add_stock(stock, sector:)`
|
|
51
|
+
|
|
52
|
+
Add a stock to sector analysis
|
|
53
|
+
|
|
54
|
+
!!! info "Parameters"
|
|
55
|
+
|
|
56
|
+
| Name | Type | Description |
|
|
57
|
+
|------|------|-------------|
|
|
58
|
+
| `stock` | `SQA::Stock, String` | Stock object or ticker |
|
|
59
|
+
| `sector` | `Symbol` | Sector classification |
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
??? info "Source Location"
|
|
63
|
+
[`lib/sqa/sector_analyzer.rb:62`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L62)
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
### `#discover_sector_patterns(sector, stocks, **options)`
|
|
68
|
+
|
|
69
|
+
Discover patterns for an entire sector
|
|
70
|
+
|
|
71
|
+
!!! info "Parameters"
|
|
72
|
+
|
|
73
|
+
| Name | Type | Description |
|
|
74
|
+
|------|------|-------------|
|
|
75
|
+
| `sector` | `Symbol` | Sector to analyze |
|
|
76
|
+
| `stocks` | `Array<SQA::Stock>` | Stock objects to analyze |
|
|
77
|
+
| `options` | `Hash` | Pattern discovery options |
|
|
78
|
+
!!! success "Returns"
|
|
79
|
+
|
|
80
|
+
**Type:** `Array<Hash>`
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
Sector-wide patterns
|
|
85
|
+
|
|
86
|
+
??? info "Source Location"
|
|
87
|
+
[`lib/sqa/sector_analyzer.rb:86`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L86)
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### `#detect_sector_regime(sector, stocks)`
|
|
92
|
+
|
|
93
|
+
Detect sector regime
|
|
94
|
+
|
|
95
|
+
!!! info "Parameters"
|
|
96
|
+
|
|
97
|
+
| Name | Type | Description |
|
|
98
|
+
|------|------|-------------|
|
|
99
|
+
| `sector` | `Symbol` | Sector to analyze |
|
|
100
|
+
| `stocks` | `Array<SQA::Stock>` | Stock objects |
|
|
101
|
+
!!! success "Returns"
|
|
102
|
+
|
|
103
|
+
**Type:** `Hash`
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
Sector regime information
|
|
108
|
+
|
|
109
|
+
??? info "Source Location"
|
|
110
|
+
[`lib/sqa/sector_analyzer.rb:146`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L146)
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### `#query_sector(sector, fact_type, pattern = {})`
|
|
115
|
+
|
|
116
|
+
Query sector blackboard
|
|
117
|
+
|
|
118
|
+
!!! info "Parameters"
|
|
119
|
+
|
|
120
|
+
| Name | Type | Description |
|
|
121
|
+
|------|------|-------------|
|
|
122
|
+
| `sector` | `Symbol` | Sector to query |
|
|
123
|
+
| `fact_type` | `Symbol` | Type of fact to query |
|
|
124
|
+
| `pattern` | `Hash` | Pattern to match |
|
|
125
|
+
!!! success "Returns"
|
|
126
|
+
|
|
127
|
+
**Type:** `Array<KBS::Fact>`
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
Matching facts
|
|
132
|
+
|
|
133
|
+
??? info "Source Location"
|
|
134
|
+
[`lib/sqa/sector_analyzer.rb:190`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L190)
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### `#print_sector_summary(sector)`
|
|
139
|
+
|
|
140
|
+
Print sector summary
|
|
141
|
+
|
|
142
|
+
!!! info "Parameters"
|
|
143
|
+
|
|
144
|
+
| Name | Type | Description |
|
|
145
|
+
|------|------|-------------|
|
|
146
|
+
| `sector` | `Symbol` | Sector to summarize |
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
??? info "Source Location"
|
|
150
|
+
[`lib/sqa/sector_analyzer.rb:202`](https://github.com/madbomber/sqa/blob/main/lib/sqa/sector_analyzer.rb#L202)
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 📝 Attributes
|
|
155
|
+
|
|
156
|
+
### 👁️ `blackboards` <small>read-only</small>
|
|
157
|
+
|
|
158
|
+
Returns the value of attribute blackboards.
|
|
159
|
+
|
|
160
|
+
### 👁️ `stocks_by_sector` <small>read-only</small>
|
|
161
|
+
|
|
162
|
+
Returns the value of attribute stocks_by_sector.
|
|
163
|
+
|