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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +154 -1
  3. data/README.md +4 -0
  4. data/Rakefile +52 -10
  5. data/docs/advanced/index.md +1 -13
  6. data/docs/api/index.md +547 -61
  7. data/docs/api-reference/alphavantageapi.md +1057 -0
  8. data/docs/api-reference/apierror.md +31 -0
  9. data/docs/api-reference/index.md +221 -0
  10. data/docs/api-reference/notimplemented.md +27 -0
  11. data/docs/api-reference/sqa.md +267 -0
  12. data/docs/api-reference/sqa_backtest.md +171 -0
  13. data/docs/api-reference/sqa_backtest_results.md +530 -0
  14. data/docs/api-reference/sqa_badparametererror.md +13 -0
  15. data/docs/api-reference/sqa_config.md +538 -0
  16. data/docs/api-reference/sqa_configurationerror.md +13 -0
  17. data/docs/api-reference/sqa_datafetcherror.md +56 -0
  18. data/docs/api-reference/sqa_dataframe.md +779 -0
  19. data/docs/api-reference/sqa_dataframe_alphavantage.md +30 -0
  20. data/docs/api-reference/sqa_dataframe_data.md +325 -0
  21. data/docs/api-reference/sqa_dataframe_yahoofinance.md +25 -0
  22. data/docs/api-reference/sqa_ensemble.md +413 -0
  23. data/docs/api-reference/sqa_fpop.md +211 -0
  24. data/docs/api-reference/sqa_geneticprogram.md +325 -0
  25. data/docs/api-reference/sqa_geneticprogram_individual.md +114 -0
  26. data/docs/api-reference/sqa_marketregime.md +212 -0
  27. data/docs/api-reference/sqa_multitimeframe.md +227 -0
  28. data/docs/api-reference/sqa_patternmatcher.md +195 -0
  29. data/docs/api-reference/sqa_pluginmanager.md +55 -0
  30. data/docs/api-reference/sqa_portfolio.md +512 -0
  31. data/docs/api-reference/sqa_portfolio_position.md +220 -0
  32. data/docs/api-reference/sqa_portfolio_trade.md +332 -0
  33. data/docs/api-reference/sqa_portfoliooptimizer.md +248 -0
  34. data/docs/api-reference/sqa_riskmanager.md +388 -0
  35. data/docs/api-reference/sqa_seasonalanalyzer.md +121 -0
  36. data/docs/api-reference/sqa_sectoranalyzer.md +163 -0
  37. data/docs/api-reference/sqa_stock.md +661 -0
  38. data/docs/api-reference/sqa_strategy.md +178 -0
  39. data/docs/api-reference/sqa_strategy_bollingerbands.md +26 -0
  40. data/docs/api-reference/sqa_strategy_common.md +29 -0
  41. data/docs/api-reference/sqa_strategy_consensus.md +129 -0
  42. data/docs/api-reference/sqa_strategy_ema.md +41 -0
  43. data/docs/api-reference/sqa_strategy_kbs.md +154 -0
  44. data/docs/api-reference/sqa_strategy_macd.md +26 -0
  45. data/docs/api-reference/sqa_strategy_mp.md +41 -0
  46. data/docs/api-reference/sqa_strategy_mr.md +41 -0
  47. data/docs/api-reference/sqa_strategy_random.md +41 -0
  48. data/docs/api-reference/sqa_strategy_rsi.md +41 -0
  49. data/docs/api-reference/sqa_strategy_sma.md +41 -0
  50. data/docs/api-reference/sqa_strategy_stochastic.md +26 -0
  51. data/docs/api-reference/sqa_strategy_volumebreakout.md +26 -0
  52. data/docs/api-reference/sqa_strategygenerator.md +298 -0
  53. data/docs/api-reference/sqa_strategygenerator_pattern.md +264 -0
  54. data/docs/api-reference/sqa_strategygenerator_patterncontext.md +326 -0
  55. data/docs/api-reference/sqa_strategygenerator_profitablepoint.md +424 -0
  56. data/docs/api-reference/sqa_stream.md +256 -0
  57. data/docs/api-reference/sqa_ticker.md +175 -0
  58. data/docs/api-reference/string.md +135 -0
  59. data/docs/assets/images/advanced-workflow.svg +89 -0
  60. data/docs/assets/images/architecture.svg +107 -0
  61. data/docs/assets/images/data-flow.svg +138 -0
  62. data/docs/assets/images/getting-started-workflow.svg +88 -0
  63. data/docs/assets/images/strategy-flow.svg +78 -0
  64. data/docs/assets/images/system-architecture.svg +150 -0
  65. data/docs/concepts/index.md +292 -19
  66. data/docs/file_formats.md +250 -0
  67. data/docs/getting-started/index.md +1 -14
  68. data/docs/index.md +26 -23
  69. data/docs/llms.txt +109 -0
  70. data/docs/strategies/kbs.md +15 -14
  71. data/docs/strategy.md +381 -3
  72. data/docs/terms_of_use.md +1 -1
  73. data/examples/README.md +10 -0
  74. data/lib/api/alpha_vantage_api.rb +3 -7
  75. data/lib/sqa/backtest.rb +32 -0
  76. data/lib/sqa/config.rb +109 -28
  77. data/lib/sqa/data_frame/data.rb +13 -1
  78. data/lib/sqa/data_frame.rb +193 -26
  79. data/lib/sqa/errors.rb +79 -17
  80. data/lib/sqa/init.rb +70 -15
  81. data/lib/sqa/pattern_matcher.rb +4 -4
  82. data/lib/sqa/portfolio.rb +55 -1
  83. data/lib/sqa/sector_analyzer.rb +3 -11
  84. data/lib/sqa/stock.rb +180 -15
  85. data/lib/sqa/strategy.rb +62 -4
  86. data/lib/sqa/ticker.rb +106 -48
  87. data/lib/sqa/version.rb +1 -1
  88. data/lib/sqa.rb +4 -4
  89. data/mkdocs.yml +69 -81
  90. metadata +89 -21
  91. data/docs/README.md +0 -43
  92. data/examples/sinatra_app/Gemfile +0 -42
  93. data/examples/sinatra_app/Gemfile.lock +0 -268
  94. data/examples/sinatra_app/QUICKSTART.md +0 -169
  95. data/examples/sinatra_app/README.md +0 -471
  96. data/examples/sinatra_app/RUNNING_WITHOUT_TALIB.md +0 -90
  97. data/examples/sinatra_app/TROUBLESHOOTING.md +0 -95
  98. data/examples/sinatra_app/app.rb +0 -404
  99. data/examples/sinatra_app/config.ru +0 -5
  100. data/examples/sinatra_app/public/css/style.css +0 -723
  101. data/examples/sinatra_app/public/debug_macd.html +0 -82
  102. data/examples/sinatra_app/public/js/app.js +0 -107
  103. data/examples/sinatra_app/start.sh +0 -53
  104. data/examples/sinatra_app/views/analyze.erb +0 -306
  105. data/examples/sinatra_app/views/backtest.erb +0 -325
  106. data/examples/sinatra_app/views/dashboard.erb +0 -831
  107. data/examples/sinatra_app/views/error.erb +0 -58
  108. data/examples/sinatra_app/views/index.erb +0 -118
  109. data/examples/sinatra_app/views/layout.erb +0 -61
  110. data/examples/sinatra_app/views/portfolio.erb +0 -43
data/docs/api/index.md CHANGED
@@ -2,125 +2,611 @@
2
2
 
3
3
  Complete API documentation for SQA classes and modules.
4
4
 
5
- ## Core Classes
5
+ !!! tip "Auto-Generated API Documentation"
6
+ For detailed API documentation with all methods, parameters, and return values, see the **[Complete API Reference](../api-reference/index.md)** - automatically generated from YARD comments with the same Material theme!
7
+
8
+ ## Quick Navigation
9
+
10
+ | Class | Description |
11
+ |-------|-------------|
12
+ | [SQA Module](#sqa-module) | Main module, initialization, configuration |
13
+ | [SQA::Stock](#sqastock) | Stock data management |
14
+ | [SQA::DataFrame](#sqadataframe) | High-performance data structures |
15
+ | [SQA::Strategy](#sqastrategy) | Trading strategy framework |
16
+ | [SQA::Portfolio](#sqaportfolio) | Position and trade tracking |
17
+ | [SQA::Backtest](#sqabacktest) | Strategy simulation |
18
+ | [SQA::Config](#sqaconfig) | Configuration management |
19
+ | [SQAI/SQA::TAI](#sqai-indicators) | Technical indicators |
6
20
 
7
- ### SQA Module
8
- Main module containing configuration and initialization.
21
+ ---
22
+
23
+ ## SQA Module
24
+
25
+ Main module containing initialization and global accessors.
26
+
27
+ ### Module Methods
28
+
29
+ #### `SQA.init(argv = ARGV)`
30
+
31
+ Initializes the SQA library. Should be called once at application startup.
32
+
33
+ ```ruby
34
+ SQA.init
35
+ # Or with arguments
36
+ SQA.init("--debug")
37
+ ```
38
+
39
+ **Returns:** `SQA::Config` - The configuration instance
40
+
41
+ #### `SQA.config`
42
+
43
+ Returns the current configuration object.
44
+
45
+ ```ruby
46
+ SQA.config.data_dir = "~/my_data"
47
+ SQA.config.debug = true
48
+ ```
49
+
50
+ **Returns:** `SQA::Config`
51
+
52
+ #### `SQA.data_dir`
53
+
54
+ Returns the data directory as a Pathname.
55
+
56
+ ```ruby
57
+ path = SQA.data_dir # => #<Pathname:/Users/you/sqa_data>
58
+ ```
59
+
60
+ **Returns:** `Pathname`
61
+
62
+ #### `SQA.av_api_key`
63
+
64
+ Returns the Alpha Vantage API key from environment variables.
65
+
66
+ ```ruby
67
+ key = SQA.av_api_key
68
+ ```
69
+
70
+ **Returns:** `String`
71
+ **Raises:** `SQA::ConfigurationError` if not set
72
+
73
+ #### `SQA.debug?` / `SQA.verbose?`
74
+
75
+ Check if debug or verbose mode is enabled.
76
+
77
+ ```ruby
78
+ puts "Debug mode" if SQA.debug?
79
+ ```
80
+
81
+ **Returns:** `Boolean`
82
+
83
+ ---
9
84
 
10
- - `SQA.init` - Initialize SQA system
11
- - `SQA.config` - Access configuration
12
- - `SQA.data_dir` - Get data directory
13
- - `SQA.av` - Alpha Vantage API client
85
+ ## SQA::Stock
14
86
 
15
- ### Stock Class
16
- Represents a stock with historical data.
87
+ Represents a stock with historical data and metadata.
88
+
89
+ ### Constructor
90
+
91
+ #### `SQA::Stock.new(ticker:, source: :alpha_vantage)`
92
+
93
+ Creates a new Stock instance and loads/fetches its data.
17
94
 
18
95
  ```ruby
19
96
  stock = SQA::Stock.new(ticker: 'AAPL')
97
+ stock = SQA::Stock.new(ticker: 'MSFT', source: :yahoo_finance)
98
+ ```
99
+
100
+ **Parameters:**
101
+ - `ticker` (String) - Stock ticker symbol
102
+ - `source` (Symbol) - Data source (`:alpha_vantage` or `:yahoo_finance`)
103
+
104
+ **Raises:** `SQA::DataFetchError` if data cannot be fetched
105
+
106
+ ### Instance Attributes
107
+
108
+ | Attribute | Type | Description |
109
+ |-----------|------|-------------|
110
+ | `ticker` | String | Stock symbol (lowercase) |
111
+ | `name` | String | Company name |
112
+ | `exchange` | String | Exchange (NASDAQ, NYSE, etc.) |
113
+ | `source` | Symbol | Data source used |
114
+ | `df` | SQA::DataFrame | Price/volume DataFrame |
115
+ | `data` | SQA::DataFrame::Data | Stock metadata |
116
+ | `indicators` | Hash | Cached indicator values |
117
+ | `overview` | Hash | Company overview from API |
118
+
119
+ ### Instance Methods
120
+
121
+ #### `#to_s` / `#inspect`
122
+
123
+ Returns human-readable string representation.
124
+
125
+ ```ruby
126
+ stock.to_s # => "aapl with 1258 data points from 2019-11-09 to 2024-11-08"
127
+ ```
128
+
129
+ #### `#update`
130
+
131
+ Updates stock's overview data from API.
132
+
133
+ #### `#save_data`
134
+
135
+ Persists metadata to JSON file.
136
+
137
+ ### Class Methods
138
+
139
+ #### `SQA::Stock.top`
140
+
141
+ Fetches top gainers, losers, and most actively traded stocks.
142
+
143
+ ```ruby
144
+ top = SQA::Stock.top
145
+ top.top_gainers.each { |s| puts s.ticker }
146
+ top.top_losers.first
147
+ top.most_actively_traded
20
148
  ```
21
149
 
22
- **Methods:**
23
- - `#ticker` - Stock symbol
24
- - `#df` - DataFrame with price/volume data
25
- - `#update` - Fetch latest data
26
- - `#save_data` - Persist to disk
150
+ **Returns:** `Hashie::Mash` with three arrays
151
+
152
+ #### `SQA::Stock.connection` / `SQA::Stock.connection=`
153
+
154
+ Get or set the Faraday connection for API requests.
155
+
156
+ ```ruby
157
+ # For testing with mocks
158
+ SQA::Stock.connection = mock_connection
159
+ ```
160
+
161
+ ---
162
+
163
+ ## SQA::DataFrame
27
164
 
28
- ### DataFrame Class
29
165
  High-performance wrapper around Polars DataFrame.
30
166
 
167
+ ### Constructor
168
+
169
+ #### `SQA::DataFrame.new(raw_data = nil, mapping: {}, transformers: {})`
170
+
171
+ Creates a new DataFrame instance.
172
+
173
+ ```ruby
174
+ df = SQA::DataFrame.new(data, mapping: { "Close" => "close_price" })
175
+ ```
176
+
177
+ ### Instance Attributes
178
+
179
+ | Attribute | Type | Description |
180
+ |-----------|------|-------------|
181
+ | `data` | Polars::DataFrame | Underlying Polars DataFrame |
182
+
183
+ ### Instance Methods
184
+
185
+ #### `#columns` / `#keys`
186
+
187
+ Returns column names.
188
+
189
+ ```ruby
190
+ df.columns # => ["timestamp", "open_price", "high_price", ...]
191
+ ```
192
+
193
+ #### `#[](column_name)`
194
+
195
+ Access a column (delegates to Polars).
196
+
31
197
  ```ruby
32
- df = stock.df
33
198
  prices = df["adj_close_price"].to_a
34
199
  ```
35
200
 
36
- **Methods:**
37
- - `#height` - Number of rows
38
- - `#column(name)` - Get column by name
39
- - `#head(n)` - First n rows
40
- - `#tail(n)` - Last n rows
201
+ #### `#size` / `#nrows` / `#length`
202
+
203
+ Returns number of rows.
204
+
205
+ ```ruby
206
+ df.size # => 1258
207
+ ```
208
+
209
+ #### `#ncols`
210
+
211
+ Returns number of columns.
212
+
213
+ #### `#to_csv(path)`
214
+
215
+ Writes DataFrame to CSV file.
216
+
217
+ ```ruby
218
+ df.to_csv("output.csv")
219
+ ```
220
+
221
+ #### `#to_h`
222
+
223
+ Converts to Ruby Hash.
224
+
225
+ ```ruby
226
+ hash = df.to_h
227
+ # => { timestamp: [...], close_price: [...], ... }
228
+ ```
229
+
230
+ #### `#append!(other_df)` / `#concat!(other_df)`
231
+
232
+ Appends another DataFrame in place.
233
+
234
+ #### `#concat_and_deduplicate!(other_df, sort_column: "timestamp")`
235
+
236
+ Appends, removes duplicates, and sorts. Enforces ascending order for TA-Lib compatibility.
237
+
238
+ #### `#rename_columns!(mapping)`
239
+
240
+ Renames columns according to mapping.
241
+
242
+ ```ruby
243
+ df.rename_columns!({ "open" => "open_price", "close" => "close_price" })
244
+ ```
245
+
246
+ #### `#apply_transformers!(transformers)`
247
+
248
+ Applies transformer functions to columns.
249
+
250
+ ```ruby
251
+ df.apply_transformers!({ "volume" => ->(v) { v.to_i } })
252
+ ```
253
+
254
+ #### `#fpl(column:, fpop:)`
255
+
256
+ Calculates Future Period Loss/Profit.
257
+
258
+ ```ruby
259
+ fpl_data = df.fpl(column: "adj_close_price", fpop: 10)
260
+ ```
261
+
262
+ #### `#fpl_analysis(column:, fpop:)`
263
+
264
+ FPL analysis with risk metrics.
265
+
266
+ ### Class Methods
267
+
268
+ #### `SQA::DataFrame.load(source:, mapping: {}, transformers: {})`
269
+
270
+ Loads DataFrame from CSV file.
271
+
272
+ ```ruby
273
+ df = SQA::DataFrame.load(source: "path/to/data.csv")
274
+ ```
275
+
276
+ #### `SQA::DataFrame.from_aofh(aofh, mapping: {}, transformers: {})`
41
277
 
42
- ### Strategy Classes
43
- Base class for all trading strategies.
278
+ Creates DataFrame from array of hashes.
44
279
 
45
280
  ```ruby
46
- signal = SQA::Strategy::RSI.trade(vector)
281
+ data = [{ "date" => "2024-01-01", "price" => 100.0 }]
282
+ df = SQA::DataFrame.from_aofh(data)
47
283
  ```
48
284
 
49
- **Common Interface:**
50
- - `.trade(vector)` - Generate trading signal
51
- - `.trade_against(vector)` - Invert signal
285
+ #### `SQA::DataFrame.from_csv_file(source, mapping: {}, transformers: {})`
52
286
 
53
- ## Advanced Classes
287
+ Creates DataFrame from CSV file.
288
+
289
+ #### `SQA::DataFrame.from_json_file(source, mapping: {}, transformers: {})`
290
+
291
+ Creates DataFrame from JSON file.
292
+
293
+ ---
294
+
295
+ ## SQA::Strategy
296
+
297
+ Framework for managing trading strategies.
298
+
299
+ ### Constructor
300
+
301
+ #### `SQA::Strategy.new`
302
+
303
+ Creates a new Strategy manager with empty collection.
304
+
305
+ ```ruby
306
+ strategy = SQA::Strategy.new
307
+ ```
308
+
309
+ ### Instance Attributes
310
+
311
+ | Attribute | Type | Description |
312
+ |-----------|------|-------------|
313
+ | `strategies` | Array<Method> | Collection of strategy methods |
314
+
315
+ ### Instance Methods
316
+
317
+ #### `#add(strategy)`
318
+
319
+ Adds a trading strategy.
320
+
321
+ ```ruby
322
+ strategy.add(SQA::Strategy::RSI)
323
+ strategy.add(MyModule.method(:custom_trade))
324
+ ```
325
+
326
+ **Parameters:**
327
+ - `strategy` (Class or Method) - Strategy to add
328
+
329
+ **Raises:** `BadParameterError` if not Class or Method
330
+
331
+ #### `#execute(vector)`
332
+
333
+ Executes all strategies with given data.
334
+
335
+ ```ruby
336
+ signals = strategy.execute(vector)
337
+ # => [:buy, :hold, :sell]
338
+ ```
339
+
340
+ **Parameters:**
341
+ - `vector` (OpenStruct) - Data for strategy analysis
342
+
343
+ **Returns:** `Array<Symbol>` - Array of `:buy`, `:sell`, or `:hold`
344
+
345
+ #### `#auto_load(except: [:common], only: [])`
346
+
347
+ Auto-loads strategy files from strategy directory.
348
+
349
+ ```ruby
350
+ strategy.auto_load(only: [:rsi, :macd])
351
+ strategy.auto_load(except: [:random])
352
+ ```
353
+
354
+ #### `#available`
355
+
356
+ Lists all available strategy classes.
357
+
358
+ ```ruby
359
+ strategy.available
360
+ # => [SQA::Strategy::RSI, SQA::Strategy::MACD, ...]
361
+ ```
362
+
363
+ ### Strategy Interface
364
+
365
+ All strategy classes must implement:
366
+
367
+ ```ruby
368
+ class SQA::Strategy::MyStrategy
369
+ def self.trade(vector)
370
+ # Returns :buy, :sell, or :hold
371
+ end
372
+ end
373
+ ```
374
+
375
+ ---
376
+
377
+ ## SQA::Portfolio
54
378
 
55
- ### Portfolio Class
56
379
  Track positions and calculate P&L.
57
380
 
381
+ ### Constructor
382
+
383
+ #### `SQA::Portfolio.new(initial_cash:, commission: 0.0)`
384
+
385
+ ```ruby
386
+ portfolio = SQA::Portfolio.new(initial_cash: 10_000, commission: 1.0)
387
+ ```
388
+
389
+ ### Instance Attributes
390
+
391
+ | Attribute | Type | Description |
392
+ |-----------|------|-------------|
393
+ | `cash` | Float | Available cash balance |
394
+ | `positions` | Hash | Ticker → share count |
395
+ | `trades` | Array | Trade history |
396
+
397
+ ### Instance Methods
398
+
399
+ #### `#buy(ticker, shares:, price:)`
400
+
401
+ Purchases shares.
402
+
58
403
  ```ruby
59
- portfolio = SQA::Portfolio.new(initial_cash: 10_000)
60
404
  portfolio.buy('AAPL', shares: 10, price: 150.0)
61
405
  ```
62
406
 
63
- ### Backtest Class
407
+ #### `#sell(ticker, shares:, price:)`
408
+
409
+ Sells shares.
410
+
411
+ ```ruby
412
+ portfolio.sell('AAPL', shares: 5, price: 160.0)
413
+ ```
414
+
415
+ #### `#value(current_prices)`
416
+
417
+ Calculates total portfolio value.
418
+
419
+ ```ruby
420
+ total = portfolio.value({ 'AAPL' => 165.0 })
421
+ ```
422
+
423
+ **Parameters:**
424
+ - `current_prices` (Hash) - Ticker → current price
425
+
426
+ ---
427
+
428
+ ## SQA::Backtest
429
+
64
430
  Simulate strategies on historical data.
65
431
 
432
+ ### Constructor
433
+
434
+ #### `SQA::Backtest.new(stock:, strategy:, initial_cash: 10_000, commission: 0.0)`
435
+
66
436
  ```ruby
67
- backtest = SQA::Backtest.new(stock: stock, strategy: SQA::Strategy::MACD)
68
- results = backtest.run
437
+ backtest = SQA::Backtest.new(
438
+ stock: stock,
439
+ strategy: SQA::Strategy::RSI,
440
+ initial_cash: 10_000,
441
+ commission: 1.0
442
+ )
69
443
  ```
70
444
 
71
- ### Stream Class
72
- Process real-time price data.
445
+ ### Instance Methods
446
+
447
+ #### `#run`
448
+
449
+ Executes the backtest simulation.
73
450
 
74
451
  ```ruby
75
- stream = SQA::Stream.new(ticker: 'AAPL', strategies: [SQA::Strategy::RSI])
76
- stream.on_signal { |signal, data| puts "Signal: #{signal}" }
452
+ results = backtest.run
77
453
  ```
78
454
 
79
- ## Indicator Functions (SQAI)
455
+ **Returns:** Results object with metrics:
456
+
457
+ | Metric | Description |
458
+ |--------|-------------|
459
+ | `total_return` | Total percentage return |
460
+ | `sharpe_ratio` | Risk-adjusted return |
461
+ | `sortino_ratio` | Downside risk-adjusted return |
462
+ | `max_drawdown` | Largest peak-to-trough decline |
463
+ | `win_rate` | Percentage of profitable trades |
464
+ | `num_trades` | Total number of trades |
465
+ | `final_value` | Ending portfolio value |
466
+
467
+ ---
468
+
469
+ ## SQA::Config
470
+
471
+ Configuration management with Hashie::Dash.
472
+
473
+ ### Properties
474
+
475
+ | Property | Type | Default | Description |
476
+ |----------|------|---------|-------------|
477
+ | `data_dir` | String | `~/sqa_data` | Data storage directory |
478
+ | `log_level` | Symbol | `:info` | Log level |
479
+ | `debug` | Boolean | `false` | Debug mode |
480
+ | `verbose` | Boolean | `false` | Verbose output |
481
+ | `lazy_update` | Boolean | `false` | Skip API updates |
482
+ | `plotting_library` | Symbol | `:gruff` | Plotting library |
483
+
484
+ ### Instance Methods
485
+
486
+ #### `#debug?` / `#verbose?`
487
+
488
+ Check mode flags.
489
+
490
+ #### `#from_file`
491
+
492
+ Loads configuration from file (YAML, TOML, or JSON).
493
+
494
+ #### `#dump_file`
495
+
496
+ Saves configuration to file.
497
+
498
+ ### Class Methods
499
+
500
+ #### `SQA::Config.reset`
501
+
502
+ Resets configuration to defaults.
503
+
504
+ #### `SQA::Config.initialized?`
80
505
 
81
- All indicators from TA-Lib are available via the `SQAI` module.
506
+ Check if config has been initialized.
507
+
508
+ ---
509
+
510
+ ## SQAI Indicators
511
+
512
+ All indicators from TA-Lib via the `sqa-tai` gem.
513
+
514
+ ### Common Usage
82
515
 
83
516
  ```ruby
84
- # Moving averages
85
- SQAI.sma(prices, period: 20)
86
- SQAI.ema(prices, period: 12)
517
+ prices = stock.df["adj_close_price"].to_a
518
+
519
+ # Moving Averages
520
+ sma = SQAI.sma(prices, period: 20)
521
+ ema = SQAI.ema(prices, period: 12)
87
522
 
88
- # Oscillators
89
- SQAI.rsi(prices, period: 14)
90
- SQAI.macd(prices, fast_period: 12, slow_period: 26, signal_period: 9)
523
+ # Momentum
524
+ rsi = SQAI.rsi(prices, period: 14)
525
+ macd, signal, hist = SQAI.macd(prices,
526
+ fast_period: 12,
527
+ slow_period: 26,
528
+ signal_period: 9
529
+ )
91
530
 
92
531
  # Volatility
93
- SQAI.bbands(prices, period: 20, nbdev_up: 2, nbdev_down: 2)
94
- SQAI.atr(high, low, close, period: 14)
532
+ upper, middle, lower = SQAI.bbands(prices, period: 20)
533
+ atr = SQAI.atr(high, low, close, period: 14)
534
+ ```
535
+
536
+ ### List All Indicators
537
+
538
+ ```ruby
539
+ SQAI.methods.grep(/^[a-z]/).sort
540
+ # => [:acos, :ad, :add, :adosc, :adx, :adxr, ...]
95
541
  ```
96
542
 
97
- See the [full indicator list](../indicators/index.md).
543
+ See [Technical Indicators](../indicators/index.md) for complete reference.
544
+
545
+ ---
546
+
547
+ ## Error Classes
98
548
 
99
- ## Configuration
549
+ ### SQA::DataFetchError
100
550
 
101
- ### Config Class
102
- Manage SQA configuration.
551
+ Raised when unable to fetch data from API or file.
103
552
 
104
553
  ```ruby
105
- config = SQA::Config.new(data_dir: "~/my_data")
554
+ begin
555
+ stock = SQA::Stock.new(ticker: 'INVALID')
556
+ rescue SQA::DataFetchError => e
557
+ puts e.message
558
+ puts e.original_error # Wrapped exception
559
+ end
106
560
  ```
107
561
 
108
- **Properties:**
109
- - `data_dir` - Data storage location
110
- - `log_level` - Logging verbosity
111
- - `debug` - Debug mode flag
562
+ ### SQA::ConfigurationError
112
563
 
113
- ## Error Classes
564
+ Raised for invalid or missing configuration.
114
565
 
115
- - `SQA::ApiError` - API request failures
116
- - `SQA::BadParameterError` - Invalid parameters
117
- - `SQA::NoDataError` - Missing data
566
+ ```ruby
567
+ begin
568
+ key = SQA.av_api_key
569
+ rescue SQA::ConfigurationError => e
570
+ puts "API key not set"
571
+ end
572
+ ```
573
+
574
+ ### SQA::BadParameterError
575
+
576
+ Raised for invalid method parameters.
577
+
578
+ ```ruby
579
+ begin
580
+ strategy.add("not a class")
581
+ rescue SQA::BadParameterError
582
+ puts "Invalid strategy type"
583
+ end
584
+ ```
585
+
586
+ ### ApiError
587
+
588
+ Raised when external API returns error response.
589
+
590
+ ### NotImplemented
591
+
592
+ Raised for unimplemented features.
118
593
 
119
594
  ---
120
595
 
121
- For detailed documentation, see the source code or use Ruby's introspection:
596
+ ## Introspection
597
+
598
+ Use Ruby introspection to explore the API:
122
599
 
123
600
  ```ruby
601
+ # List instance methods
124
602
  SQA::Stock.instance_methods(false)
603
+
604
+ # List class methods
605
+ SQA::Stock.methods(false)
606
+
607
+ # Check method signature
608
+ SQA::Stock.instance_method(:initialize).parameters
609
+
610
+ # List available indicators
125
611
  SQAI.methods.grep(/^[a-z]/).sort
126
612
  ```