sqa 0.0.24 → 0.0.31

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 (180) hide show
  1. checksums.yaml +4 -4
  2. data/.goose/memory/development.txt +3 -0
  3. data/.semver +6 -0
  4. data/ARCHITECTURE.md +648 -0
  5. data/CHANGELOG.md +82 -0
  6. data/CLAUDE.md +653 -0
  7. data/COMMITS.md +196 -0
  8. data/DATAFRAME_ARCHITECTURE_REVIEW.md +421 -0
  9. data/NEXT-STEPS.md +154 -0
  10. data/README.md +812 -262
  11. data/TASKS.md +358 -0
  12. data/TEST_RESULTS.md +140 -0
  13. data/TODO.md +42 -0
  14. data/_notes.txt +25 -0
  15. data/bin/sqa-console +11 -0
  16. data/data/talk_talk.json +103284 -0
  17. data/develop_summary.md +313 -0
  18. data/docs/advanced/backtesting.md +206 -0
  19. data/docs/advanced/ensemble.md +68 -0
  20. data/docs/advanced/fpop.md +153 -0
  21. data/docs/advanced/index.md +112 -0
  22. data/docs/advanced/multi-timeframe.md +67 -0
  23. data/docs/advanced/pattern-matcher.md +75 -0
  24. data/docs/advanced/portfolio-optimizer.md +79 -0
  25. data/docs/advanced/portfolio.md +166 -0
  26. data/docs/advanced/risk-management.md +210 -0
  27. data/docs/advanced/strategy-generator.md +158 -0
  28. data/docs/advanced/streaming.md +209 -0
  29. data/docs/ai_and_ml.md +80 -0
  30. data/docs/api/dataframe.md +1115 -0
  31. data/docs/api/index.md +126 -0
  32. data/docs/assets/css/custom.css +88 -0
  33. data/docs/assets/js/mathjax.js +18 -0
  34. data/docs/concepts/index.md +68 -0
  35. data/docs/contributing/index.md +60 -0
  36. data/docs/data-sources/index.md +66 -0
  37. data/docs/data_frame.md +317 -97
  38. data/docs/factors_that_impact_price.md +26 -0
  39. data/docs/finviz.md +11 -0
  40. data/docs/fx_pro_bit.md +25 -0
  41. data/docs/genetic_programming.md +104 -0
  42. data/docs/getting-started/index.md +123 -0
  43. data/docs/getting-started/installation.md +229 -0
  44. data/docs/getting-started/quick-start.md +244 -0
  45. data/docs/i_gotta_an_idea.md +22 -0
  46. data/docs/index.md +163 -0
  47. data/docs/indicators/index.md +97 -0
  48. data/docs/indicators.md +110 -24
  49. data/docs/options.md +8 -0
  50. data/docs/strategies/bollinger-bands.md +146 -0
  51. data/docs/strategies/consensus.md +64 -0
  52. data/docs/strategies/custom.md +310 -0
  53. data/docs/strategies/ema.md +53 -0
  54. data/docs/strategies/index.md +92 -0
  55. data/docs/strategies/kbs.md +164 -0
  56. data/docs/strategies/macd.md +96 -0
  57. data/docs/strategies/market-profile.md +54 -0
  58. data/docs/strategies/mean-reversion.md +58 -0
  59. data/docs/strategies/rsi.md +95 -0
  60. data/docs/strategies/sma.md +55 -0
  61. data/docs/strategies/stochastic.md +63 -0
  62. data/docs/strategies/volume-breakout.md +54 -0
  63. data/docs/tags.md +7 -0
  64. data/docs/true_strength_index.md +46 -0
  65. data/docs/weighted_moving_average.md +48 -0
  66. data/examples/README.md +354 -0
  67. data/examples/advanced_features_example.rb +350 -0
  68. data/examples/fpop_analysis_example.rb +191 -0
  69. data/examples/genetic_programming_example.rb +148 -0
  70. data/examples/kbs_strategy_example.rb +208 -0
  71. data/examples/pattern_context_example.rb +300 -0
  72. data/examples/rails_app/Gemfile +34 -0
  73. data/examples/rails_app/README.md +416 -0
  74. data/examples/rails_app/app/assets/javascripts/application.js +107 -0
  75. data/examples/rails_app/app/assets/stylesheets/application.css +659 -0
  76. data/examples/rails_app/app/controllers/analysis_controller.rb +11 -0
  77. data/examples/rails_app/app/controllers/api/v1/stocks_controller.rb +227 -0
  78. data/examples/rails_app/app/controllers/application_controller.rb +22 -0
  79. data/examples/rails_app/app/controllers/backtest_controller.rb +11 -0
  80. data/examples/rails_app/app/controllers/dashboard_controller.rb +21 -0
  81. data/examples/rails_app/app/controllers/portfolio_controller.rb +7 -0
  82. data/examples/rails_app/app/views/analysis/show.html.erb +209 -0
  83. data/examples/rails_app/app/views/backtest/show.html.erb +171 -0
  84. data/examples/rails_app/app/views/dashboard/index.html.erb +118 -0
  85. data/examples/rails_app/app/views/dashboard/show.html.erb +408 -0
  86. data/examples/rails_app/app/views/errors/show.html.erb +17 -0
  87. data/examples/rails_app/app/views/layouts/application.html.erb +60 -0
  88. data/examples/rails_app/app/views/portfolio/index.html.erb +33 -0
  89. data/examples/rails_app/bin/rails +6 -0
  90. data/examples/rails_app/config/application.rb +45 -0
  91. data/examples/rails_app/config/boot.rb +5 -0
  92. data/examples/rails_app/config/database.yml +18 -0
  93. data/examples/rails_app/config/environment.rb +11 -0
  94. data/examples/rails_app/config/routes.rb +26 -0
  95. data/examples/rails_app/config.ru +8 -0
  96. data/examples/realtime_stream_example.rb +274 -0
  97. data/examples/sinatra_app/Gemfile +22 -0
  98. data/examples/sinatra_app/QUICKSTART.md +159 -0
  99. data/examples/sinatra_app/README.md +461 -0
  100. data/examples/sinatra_app/app.rb +344 -0
  101. data/examples/sinatra_app/config.ru +5 -0
  102. data/examples/sinatra_app/public/css/style.css +659 -0
  103. data/examples/sinatra_app/public/js/app.js +107 -0
  104. data/examples/sinatra_app/views/analyze.erb +306 -0
  105. data/examples/sinatra_app/views/backtest.erb +325 -0
  106. data/examples/sinatra_app/views/dashboard.erb +419 -0
  107. data/examples/sinatra_app/views/error.erb +58 -0
  108. data/examples/sinatra_app/views/index.erb +118 -0
  109. data/examples/sinatra_app/views/layout.erb +61 -0
  110. data/examples/sinatra_app/views/portfolio.erb +43 -0
  111. data/examples/strategy_generator_example.rb +346 -0
  112. data/hsa_portfolio.csv +11 -0
  113. data/justfile +0 -0
  114. data/lib/api/alpha_vantage_api.rb +462 -0
  115. data/lib/sqa/backtest.rb +329 -0
  116. data/lib/sqa/data_frame/alpha_vantage.rb +43 -65
  117. data/lib/sqa/data_frame/data.rb +92 -0
  118. data/lib/sqa/data_frame/yahoo_finance.rb +35 -43
  119. data/lib/sqa/data_frame.rb +148 -243
  120. data/lib/sqa/ensemble.rb +359 -0
  121. data/lib/sqa/fpop.rb +199 -0
  122. data/lib/sqa/gp.rb +259 -0
  123. data/lib/sqa/indicator.rb +5 -8
  124. data/lib/sqa/init.rb +15 -8
  125. data/lib/sqa/market_regime.rb +240 -0
  126. data/lib/sqa/multi_timeframe.rb +379 -0
  127. data/lib/sqa/pattern_matcher.rb +497 -0
  128. data/lib/sqa/portfolio.rb +260 -6
  129. data/lib/sqa/portfolio_optimizer.rb +377 -0
  130. data/lib/sqa/risk_manager.rb +442 -0
  131. data/lib/sqa/seasonal_analyzer.rb +209 -0
  132. data/lib/sqa/sector_analyzer.rb +300 -0
  133. data/lib/sqa/stock.rb +67 -125
  134. data/lib/sqa/strategy/bollinger_bands.rb +42 -0
  135. data/lib/sqa/strategy/consensus.rb +5 -2
  136. data/lib/sqa/strategy/kbs_strategy.rb +470 -0
  137. data/lib/sqa/strategy/macd.rb +46 -0
  138. data/lib/sqa/strategy/mp.rb +1 -1
  139. data/lib/sqa/strategy/stochastic.rb +60 -0
  140. data/lib/sqa/strategy/volume_breakout.rb +57 -0
  141. data/lib/sqa/strategy.rb +5 -0
  142. data/lib/sqa/strategy_generator.rb +947 -0
  143. data/lib/sqa/stream.rb +361 -0
  144. data/lib/sqa/version.rb +1 -7
  145. data/lib/sqa.rb +23 -16
  146. data/main.just +81 -0
  147. data/mkdocs.yml +288 -0
  148. data/trace.log +0 -0
  149. metadata +261 -51
  150. data/bin/sqa +0 -6
  151. data/lib/patches/dry-cli.rb +0 -228
  152. data/lib/sqa/activity.rb +0 -10
  153. data/lib/sqa/cli.rb +0 -62
  154. data/lib/sqa/commands/analysis.rb +0 -309
  155. data/lib/sqa/commands/base.rb +0 -139
  156. data/lib/sqa/commands/web.rb +0 -199
  157. data/lib/sqa/commands.rb +0 -22
  158. data/lib/sqa/constants.rb +0 -23
  159. data/lib/sqa/indicator/average_true_range.rb +0 -33
  160. data/lib/sqa/indicator/bollinger_bands.rb +0 -28
  161. data/lib/sqa/indicator/candlestick_pattern_recognizer.rb +0 -60
  162. data/lib/sqa/indicator/donchian_channel.rb +0 -29
  163. data/lib/sqa/indicator/double_top_bottom_pattern.rb +0 -34
  164. data/lib/sqa/indicator/elliott_wave_theory.rb +0 -57
  165. data/lib/sqa/indicator/exponential_moving_average.rb +0 -25
  166. data/lib/sqa/indicator/exponential_moving_average_trend.rb +0 -36
  167. data/lib/sqa/indicator/fibonacci_retracement.rb +0 -23
  168. data/lib/sqa/indicator/head_and_shoulders_pattern.rb +0 -26
  169. data/lib/sqa/indicator/market_profile.rb +0 -32
  170. data/lib/sqa/indicator/mean_reversion.rb +0 -37
  171. data/lib/sqa/indicator/momentum.rb +0 -28
  172. data/lib/sqa/indicator/moving_average_convergence_divergence.rb +0 -29
  173. data/lib/sqa/indicator/peaks_and_valleys.rb +0 -29
  174. data/lib/sqa/indicator/predict_next_value.rb +0 -202
  175. data/lib/sqa/indicator/relative_strength_index.rb +0 -47
  176. data/lib/sqa/indicator/simple_moving_average.rb +0 -24
  177. data/lib/sqa/indicator/simple_moving_average_trend.rb +0 -32
  178. data/lib/sqa/indicator/stochastic_oscillator.rb +0 -68
  179. data/lib/sqa/indicator/true_range.rb +0 -39
  180. data/lib/sqa/trade.rb +0 -26
data/docs/api/index.md ADDED
@@ -0,0 +1,126 @@
1
+ # API Reference
2
+
3
+ Complete API documentation for SQA classes and modules.
4
+
5
+ ## Core Classes
6
+
7
+ ### SQA Module
8
+ Main module containing configuration and initialization.
9
+
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
14
+
15
+ ### Stock Class
16
+ Represents a stock with historical data.
17
+
18
+ ```ruby
19
+ stock = SQA::Stock.new(ticker: 'AAPL')
20
+ ```
21
+
22
+ **Methods:**
23
+ - `#ticker` - Stock symbol
24
+ - `#df` - DataFrame with price/volume data
25
+ - `#update` - Fetch latest data
26
+ - `#save_data` - Persist to disk
27
+
28
+ ### DataFrame Class
29
+ High-performance wrapper around Polars DataFrame.
30
+
31
+ ```ruby
32
+ df = stock.df
33
+ prices = df["adj_close_price"].to_a
34
+ ```
35
+
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
41
+
42
+ ### Strategy Classes
43
+ Base class for all trading strategies.
44
+
45
+ ```ruby
46
+ signal = SQA::Strategy::RSI.trade(vector)
47
+ ```
48
+
49
+ **Common Interface:**
50
+ - `.trade(vector)` - Generate trading signal
51
+ - `.trade_against(vector)` - Invert signal
52
+
53
+ ## Advanced Classes
54
+
55
+ ### Portfolio Class
56
+ Track positions and calculate P&L.
57
+
58
+ ```ruby
59
+ portfolio = SQA::Portfolio.new(initial_cash: 10_000)
60
+ portfolio.buy('AAPL', shares: 10, price: 150.0)
61
+ ```
62
+
63
+ ### Backtest Class
64
+ Simulate strategies on historical data.
65
+
66
+ ```ruby
67
+ backtest = SQA::Backtest.new(stock: stock, strategy: SQA::Strategy::MACD)
68
+ results = backtest.run
69
+ ```
70
+
71
+ ### Stream Class
72
+ Process real-time price data.
73
+
74
+ ```ruby
75
+ stream = SQA::Stream.new(ticker: 'AAPL', strategies: [SQA::Strategy::RSI])
76
+ stream.on_signal { |signal, data| puts "Signal: #{signal}" }
77
+ ```
78
+
79
+ ## Indicator Functions (SQAI)
80
+
81
+ All indicators from TA-Lib are available via the `SQAI` module.
82
+
83
+ ```ruby
84
+ # Moving averages
85
+ SQAI.sma(prices, period: 20)
86
+ SQAI.ema(prices, period: 12)
87
+
88
+ # Oscillators
89
+ SQAI.rsi(prices, period: 14)
90
+ SQAI.macd(prices, fast_period: 12, slow_period: 26, signal_period: 9)
91
+
92
+ # Volatility
93
+ SQAI.bbands(prices, period: 20, nbdev_up: 2, nbdev_down: 2)
94
+ SQAI.atr(high, low, close, period: 14)
95
+ ```
96
+
97
+ See the [full indicator list](../indicators/index.md).
98
+
99
+ ## Configuration
100
+
101
+ ### Config Class
102
+ Manage SQA configuration.
103
+
104
+ ```ruby
105
+ config = SQA::Config.new(data_dir: "~/my_data")
106
+ ```
107
+
108
+ **Properties:**
109
+ - `data_dir` - Data storage location
110
+ - `log_level` - Logging verbosity
111
+ - `debug` - Debug mode flag
112
+
113
+ ## Error Classes
114
+
115
+ - `SQA::ApiError` - API request failures
116
+ - `SQA::BadParameterError` - Invalid parameters
117
+ - `SQA::NoDataError` - Missing data
118
+
119
+ ---
120
+
121
+ For detailed documentation, see the source code or use Ruby's introspection:
122
+
123
+ ```ruby
124
+ SQA::Stock.instance_methods(false)
125
+ SQAI.methods.grep(/^[a-z]/).sort
126
+ ```
@@ -0,0 +1,88 @@
1
+ /* Custom styles for SQA documentation */
2
+
3
+ :root {
4
+ --md-primary-fg-color: #3f51b5;
5
+ --md-accent-fg-color: #673ab7;
6
+ }
7
+
8
+ /* Enhanced code blocks */
9
+ .highlight {
10
+ border-radius: 4px;
11
+ }
12
+
13
+ /* Better tables */
14
+ table {
15
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
16
+ }
17
+
18
+ /* Card styling for grid layouts */
19
+ .md-typeset .grid.cards > * {
20
+ border: 1px solid var(--md-default-fg-color--lightest);
21
+ border-radius: 4px;
22
+ transition: all 0.2s ease-in-out;
23
+ }
24
+
25
+ .md-typeset .grid.cards > *:hover {
26
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
27
+ transform: translateY(-2px);
28
+ }
29
+
30
+ /* Admonition enhancements */
31
+ .admonition {
32
+ border-left-width: 4px;
33
+ }
34
+
35
+ /* Code inline emphasis */
36
+ code {
37
+ background-color: var(--md-code-bg-color);
38
+ border-radius: 2px;
39
+ padding: 0.1em 0.3em;
40
+ }
41
+
42
+ /* Better h1 styling */
43
+ .md-typeset h1 {
44
+ font-weight: 600;
45
+ letter-spacing: -0.02em;
46
+ }
47
+
48
+ /* Footer enhancement */
49
+ .md-footer-meta {
50
+ background-color: var(--md-footer-bg-color);
51
+ }
52
+
53
+ /* Responsive images */
54
+ .md-typeset img {
55
+ max-width: 100%;
56
+ height: auto;
57
+ }
58
+
59
+ /* Warning box for trading disclaimers */
60
+ .md-typeset .admonition.warning {
61
+ border-left-color: #ff9800;
62
+ }
63
+
64
+ /* Success indicators */
65
+ .md-typeset .admonition.tip {
66
+ border-left-color: #00c853;
67
+ }
68
+
69
+ /* Mermaid diagram styling */
70
+ .mermaid {
71
+ text-align: center;
72
+ margin: 1em 0;
73
+ }
74
+
75
+ /* Better spacing for navigation tabs */
76
+ .md-tabs {
77
+ border-bottom: 1px solid var(--md-default-fg-color--lightest);
78
+ }
79
+
80
+ /* Code copy button enhancement */
81
+ .md-clipboard {
82
+ transition: opacity 0.2s;
83
+ }
84
+
85
+ /* Table of contents highlighting */
86
+ .md-sidebar--secondary .md-nav__link--active {
87
+ font-weight: 600;
88
+ }
@@ -0,0 +1,18 @@
1
+ // MathJax configuration for SQA documentation
2
+
3
+ window.MathJax = {
4
+ tex: {
5
+ inlineMath: [["\\(", "\\)"]],
6
+ displayMath: [["\\[", "\\]"]],
7
+ processEscapes: true,
8
+ processEnvironments: true
9
+ },
10
+ options: {
11
+ ignoreHtmlClass: ".*|",
12
+ processHtmlClass: "arithmatex"
13
+ }
14
+ };
15
+
16
+ document$.subscribe(() => {
17
+ MathJax.typesetPromise()
18
+ })
@@ -0,0 +1,68 @@
1
+ # Core Concepts
2
+
3
+ Understanding the fundamental building blocks of SQA.
4
+
5
+ ## Overview
6
+
7
+ SQA is built around several key concepts that work together to provide a comprehensive stock analysis framework:
8
+
9
+ - **Stock Objects** - Represent individual stocks with historical data
10
+ - **DataFrames** - High-performance time series data structures
11
+ - **Technical Indicators** - Mathematical calculations on price/volume data
12
+ - **Trading Strategies** - Rules for generating buy/sell/hold signals
13
+ - **Portfolio Management** - Track positions and calculate P&L
14
+ - **Backtesting** - Simulate strategies on historical data
15
+
16
+ ## Architecture Diagram
17
+
18
+ ```mermaid
19
+ graph TB
20
+ A[Data Source] -->|Fetch| B[Stock Object]
21
+ B -->|Contains| C[DataFrame]
22
+ C -->|Calculate| D[Technical Indicators]
23
+ D -->|Feed| E[Trading Strategies]
24
+ E -->|Generate| F[Trading Signals]
25
+ F -->|Execute| G[Portfolio]
26
+ G -->|Track| H[Trades & P/L]
27
+
28
+ E -->|Test| I[Backtest]
29
+ I -->|Evaluate| J[Performance Metrics]
30
+ ```
31
+
32
+ ## Learn More
33
+
34
+ <div class="grid cards" markdown>
35
+
36
+ - :material-chart-line:{ .lg .middle } __Stock Objects__
37
+
38
+ ---
39
+
40
+ Learn about loading and managing stock data
41
+
42
+ [:octicons-arrow-right-24: Stock Guide](stock.md)
43
+
44
+ - :material-table:{ .lg .middle } __DataFrames__
45
+
46
+ ---
47
+
48
+ High-performance data structures powered by Polars
49
+
50
+ [:octicons-arrow-right-24: DataFrame Guide](../data_frame.md)
51
+
52
+ - :material-chart-bell-curve:{ .lg .middle } __Indicators__
53
+
54
+ ---
55
+
56
+ 150+ technical analysis indicators via TA-Lib
57
+
58
+ [:octicons-arrow-right-24: Indicators](indicators.md)
59
+
60
+ - :material-strategy:{ .lg .middle } __Strategies__
61
+
62
+ ---
63
+
64
+ Framework for creating and executing trading strategies
65
+
66
+ [:octicons-arrow-right-24: Strategies](../strategy.md)
67
+
68
+ </div>
@@ -0,0 +1,60 @@
1
+ # Contributing to SQA
2
+
3
+ Thank you for your interest in contributing to SQA!
4
+
5
+ ## Ways to Contribute
6
+
7
+ - Report bugs
8
+ - Suggest features
9
+ - Improve documentation
10
+ - Submit pull requests
11
+ - Write tests
12
+
13
+ ## Getting Started
14
+
15
+ 1. Fork the repository
16
+ 2. Create a feature branch
17
+ 3. Make your changes
18
+ 4. Run tests
19
+ 5. Submit a pull request
20
+
21
+ ## Development Setup
22
+
23
+ ```bash
24
+ git clone https://github.com/madbomber/sqa.git
25
+ cd sqa
26
+ bundle install
27
+ ```
28
+
29
+ ## Running Tests
30
+
31
+ ```bash
32
+ # Run all tests
33
+ rake test
34
+
35
+ # Run specific test file
36
+ ruby -Ilib:test test/strategy/rsi_test.rb
37
+
38
+ # With coverage
39
+ rake test
40
+ open coverage/index.html
41
+ ```
42
+
43
+ ## Code Style
44
+
45
+ - Follow Ruby community style guidelines
46
+ - Use meaningful variable names
47
+ - Add comments for complex logic
48
+ - Keep methods focused and small
49
+
50
+ ## Pull Request Process
51
+
52
+ 1. Update documentation
53
+ 2. Add tests for new features
54
+ 3. Ensure all tests pass
55
+ 4. Update CHANGELOG.md
56
+ 5. Submit PR with clear description
57
+
58
+ ## Questions?
59
+
60
+ Open an issue on GitHub or start a discussion.
@@ -0,0 +1,66 @@
1
+ # Data Sources
2
+
3
+ SQA supports multiple data sources for historical stock price data.
4
+
5
+ ## Available Data Sources
6
+
7
+ ### Alpha Vantage (Primary)
8
+ Free API with generous limits for historical and real-time data.
9
+
10
+ **Setup:**
11
+ ```bash
12
+ export AV_API_KEY="your_key_here"
13
+ ```
14
+
15
+ **Features:**
16
+ - Daily historical data
17
+ - Adjusted closing prices
18
+ - Up to 20 years of history
19
+ - API key required (free)
20
+
21
+ [Get API Key →](https://www.alphavantage.co/support/#api-key)
22
+
23
+ ### Yahoo Finance (Fallback)
24
+ Web scraping fallback for when Alpha Vantage is unavailable.
25
+
26
+ **Features:**
27
+ - No API key required
28
+ - Less reliable (web scraping)
29
+ - Good for testing
30
+
31
+ ### CSV Files (Custom)
32
+ Import your own data from CSV files.
33
+
34
+ **Format:**
35
+ ```csv
36
+ Date,Open,High,Low,Close,Adj Close,Volume
37
+ 2024-01-01,150.0,152.0,149.0,151.0,151.0,1000000
38
+ ```
39
+
40
+ Place CSV files in `~/sqa_data/` named as `{ticker}.csv`.
41
+
42
+ ## Data Format
43
+
44
+ SQA uses a standardized column format:
45
+
46
+ - `timestamp` - Date of trading day
47
+ - `open_price` - Opening price
48
+ - `high_price` - Highest price
49
+ - `low_price` - Lowest price
50
+ - `close_price` - Closing price
51
+ - `adj_close_price` - Adjusted closing price
52
+ - `volume` - Trading volume
53
+
54
+ ## Configuration
55
+
56
+ Set data directory in config:
57
+
58
+ ```ruby
59
+ SQA.config.data_dir = "/path/to/data"
60
+ ```
61
+
62
+ Or via environment:
63
+
64
+ ```bash
65
+ export SQA_DATA_DIR="/path/to/data"
66
+ ```