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,88 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1400 450" width="1400" height="450">
|
|
2
|
+
<defs>
|
|
3
|
+
<style>
|
|
4
|
+
.box { stroke: #ffffff; stroke-width: 3; }
|
|
5
|
+
.text { fill: #ffffff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 15px; font-weight: 600; text-anchor: middle; }
|
|
6
|
+
.small-text { fill: #ffffff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 13px; font-weight: 500; text-anchor: middle; }
|
|
7
|
+
.arrow { stroke: #ffffff; stroke-width: 2.5; fill: none; marker-end: url(#arrowhead); }
|
|
8
|
+
.diamond { stroke: #ffffff; stroke-width: 3; }
|
|
9
|
+
.label { fill: #ffffff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 14px; font-weight: 500; }
|
|
10
|
+
</style>
|
|
11
|
+
<marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
12
|
+
<polygon points="0 0, 10 3, 0 6" fill="#ffffff" />
|
|
13
|
+
</marker>
|
|
14
|
+
</defs>
|
|
15
|
+
|
|
16
|
+
<!-- Install SQA -->
|
|
17
|
+
<rect x="30" y="180" width="150" height="70" rx="8" class="box" fill="#2E86DE"/>
|
|
18
|
+
<text x="105" y="210" class="text">Install</text>
|
|
19
|
+
<text x="105" y="230" class="text">SQA</text>
|
|
20
|
+
|
|
21
|
+
<!-- Configure API Keys -->
|
|
22
|
+
<rect x="220" y="180" width="150" height="70" rx="8" class="box" fill="#3867D6"/>
|
|
23
|
+
<text x="295" y="210" class="text">Configure</text>
|
|
24
|
+
<text x="295" y="230" class="text">API Keys</text>
|
|
25
|
+
|
|
26
|
+
<!-- Load Stock Data -->
|
|
27
|
+
<rect x="410" y="180" width="150" height="70" rx="8" class="box" fill="#10AC84"/>
|
|
28
|
+
<text x="485" y="210" class="text">Load Stock</text>
|
|
29
|
+
<text x="485" y="230" class="text">Data</text>
|
|
30
|
+
|
|
31
|
+
<!-- Calculate Indicators -->
|
|
32
|
+
<rect x="600" y="180" width="150" height="70" rx="8" class="box" fill="#EE5A6F"/>
|
|
33
|
+
<text x="675" y="210" class="text">Calculate</text>
|
|
34
|
+
<text x="675" y="230" class="text">Indicators</text>
|
|
35
|
+
|
|
36
|
+
<!-- Apply Strategies -->
|
|
37
|
+
<rect x="790" y="180" width="150" height="70" rx="8" class="box" fill="#F368E0"/>
|
|
38
|
+
<text x="865" y="210" class="text">Apply</text>
|
|
39
|
+
<text x="865" y="230" class="text">Strategies</text>
|
|
40
|
+
|
|
41
|
+
<!-- Analysis Type Diamond -->
|
|
42
|
+
<g transform="translate(1030, 215)">
|
|
43
|
+
<polygon points="0,-50 70,0 0,50 -70,0" class="diamond" fill="#FD79A8"/>
|
|
44
|
+
<text x="0" y="-5" class="small-text">Analysis</text>
|
|
45
|
+
<text x="0" y="12" class="small-text">Type</text>
|
|
46
|
+
</g>
|
|
47
|
+
|
|
48
|
+
<!-- Run Backtest -->
|
|
49
|
+
<rect x="1155" y="50" width="150" height="70" rx="8" class="box" fill="#FF9F43"/>
|
|
50
|
+
<text x="1230" y="80" class="text">Run</text>
|
|
51
|
+
<text x="1230" y="100" class="text">Backtest</text>
|
|
52
|
+
|
|
53
|
+
<!-- Stream Real-Time -->
|
|
54
|
+
<rect x="1155" y="180" width="150" height="70" rx="8" class="box" fill="#FFA502"/>
|
|
55
|
+
<text x="1230" y="210" class="text">Stream</text>
|
|
56
|
+
<text x="1230" y="230" class="text">Real-Time</text>
|
|
57
|
+
|
|
58
|
+
<!-- Explore in Console -->
|
|
59
|
+
<rect x="1155" y="310" width="150" height="70" rx="8" class="box" fill="#FF6348"/>
|
|
60
|
+
<text x="1230" y="333" class="text">Explore in</text>
|
|
61
|
+
<text x="1230" y="353" class="text">Console</text>
|
|
62
|
+
|
|
63
|
+
<!-- Review Results -->
|
|
64
|
+
<rect x="1155" y="420" width="150" height="50" rx="8" class="box" fill="#26DE81"/>
|
|
65
|
+
<text x="1230" y="450" class="text">Review Results</text>
|
|
66
|
+
|
|
67
|
+
<!-- Arrows - Main flow -->
|
|
68
|
+
<path d="M 180 215 L 220 215" class="arrow"/>
|
|
69
|
+
<path d="M 370 215 L 410 215" class="arrow"/>
|
|
70
|
+
<path d="M 560 215 L 600 215" class="arrow"/>
|
|
71
|
+
<path d="M 750 215 L 790 215" class="arrow"/>
|
|
72
|
+
<path d="M 940 215 L 960 215" class="arrow"/>
|
|
73
|
+
|
|
74
|
+
<!-- Arrows from diamond -->
|
|
75
|
+
<path d="M 1030 165 L 1030 85 L 1155 85" class="arrow"/>
|
|
76
|
+
<path d="M 1100 215 L 1155 215" class="arrow"/>
|
|
77
|
+
<path d="M 1030 265 L 1030 345 L 1155 345" class="arrow"/>
|
|
78
|
+
|
|
79
|
+
<!-- Arrows to Review Results -->
|
|
80
|
+
<path d="M 1230 120 L 1230 420" class="arrow"/>
|
|
81
|
+
<path d="M 1230 250 L 1230 420" class="arrow"/>
|
|
82
|
+
<path d="M 1230 380 L 1230 420" class="arrow"/>
|
|
83
|
+
|
|
84
|
+
<!-- Labels on decision paths -->
|
|
85
|
+
<text x="1090" y="115" class="label">Backtest</text>
|
|
86
|
+
<text x="1120" y="210" class="label">Live</text>
|
|
87
|
+
<text x="1090" y="305" class="label">Research</text>
|
|
88
|
+
</svg>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 650" width="800" height="650">
|
|
2
|
+
<defs>
|
|
3
|
+
<style>
|
|
4
|
+
.box { stroke: #ffffff; stroke-width: 3; }
|
|
5
|
+
.text { fill: #ffffff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 16px; font-weight: 600; text-anchor: middle; }
|
|
6
|
+
.arrow { stroke: #ffffff; stroke-width: 2.5; fill: none; marker-end: url(#arrowhead); }
|
|
7
|
+
.diamond { stroke: #ffffff; stroke-width: 3; }
|
|
8
|
+
.label { fill: #ffffff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 14px; font-weight: 500; }
|
|
9
|
+
</style>
|
|
10
|
+
<marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
11
|
+
<polygon points="0 0, 10 3, 0 6" fill="#ffffff" />
|
|
12
|
+
</marker>
|
|
13
|
+
</defs>
|
|
14
|
+
|
|
15
|
+
<!-- Price Data -->
|
|
16
|
+
<rect x="300" y="30" width="200" height="70" rx="8" class="box" fill="#2E86DE"/>
|
|
17
|
+
<text x="400" y="70" class="text">Price Data</text>
|
|
18
|
+
|
|
19
|
+
<!-- Technical Indicators -->
|
|
20
|
+
<rect x="300" y="150" width="200" height="70" rx="8" class="box" fill="#EE5A6F"/>
|
|
21
|
+
<text x="400" y="182" class="text">Technical</text>
|
|
22
|
+
<text x="400" y="202" class="text">Indicators</text>
|
|
23
|
+
|
|
24
|
+
<!-- Strategy Vector -->
|
|
25
|
+
<rect x="300" y="270" width="200" height="70" rx="8" class="box" fill="#10AC84"/>
|
|
26
|
+
<text x="400" y="302" class="text">Strategy</text>
|
|
27
|
+
<text x="400" y="322" class="text">Vector</text>
|
|
28
|
+
|
|
29
|
+
<!-- Trading Strategy -->
|
|
30
|
+
<rect x="300" y="390" width="200" height="70" rx="8" class="box" fill="#F368E0"/>
|
|
31
|
+
<text x="400" y="422" class="text">Trading</text>
|
|
32
|
+
<text x="400" y="442" class="text">Strategy</text>
|
|
33
|
+
|
|
34
|
+
<!-- Signal Diamond -->
|
|
35
|
+
<g transform="translate(400, 540)">
|
|
36
|
+
<polygon points="0,-50 70,0 0,50 -70,0" class="diamond" fill="#FD79A8"/>
|
|
37
|
+
<text x="0" y="5" class="text">Signal</text>
|
|
38
|
+
</g>
|
|
39
|
+
|
|
40
|
+
<!-- Buy Action -->
|
|
41
|
+
<rect x="50" y="580" width="150" height="60" rx="8" class="box" fill="#26DE81"/>
|
|
42
|
+
<text x="125" y="615" class="text">Buy Action</text>
|
|
43
|
+
|
|
44
|
+
<!-- Sell Action -->
|
|
45
|
+
<rect x="325" y="580" width="150" height="60" rx="8" class="box" fill="#FC5C65"/>
|
|
46
|
+
<text x="400" y="615" class="text">Sell Action</text>
|
|
47
|
+
|
|
48
|
+
<!-- No Action (Hold) -->
|
|
49
|
+
<rect x="600" y="580" width="150" height="60" rx="8" class="box" fill="#FED330"/>
|
|
50
|
+
<text x="675" y="615" class="text">No Action</text>
|
|
51
|
+
|
|
52
|
+
<!-- Arrows -->
|
|
53
|
+
<!-- Price Data to Technical Indicators -->
|
|
54
|
+
<path d="M 400 100 L 400 150" class="arrow"/>
|
|
55
|
+
|
|
56
|
+
<!-- Technical Indicators to Strategy Vector -->
|
|
57
|
+
<path d="M 400 220 L 400 270" class="arrow"/>
|
|
58
|
+
|
|
59
|
+
<!-- Strategy Vector to Trading Strategy -->
|
|
60
|
+
<path d="M 400 340 L 400 390" class="arrow"/>
|
|
61
|
+
|
|
62
|
+
<!-- Trading Strategy to Signal -->
|
|
63
|
+
<path d="M 400 460 L 400 490" class="arrow"/>
|
|
64
|
+
|
|
65
|
+
<!-- Signal to Buy -->
|
|
66
|
+
<path d="M 330 540 L 200 580" class="arrow"/>
|
|
67
|
+
|
|
68
|
+
<!-- Signal to Sell -->
|
|
69
|
+
<path d="M 400 590 L 400 580" class="arrow"/>
|
|
70
|
+
|
|
71
|
+
<!-- Signal to Hold -->
|
|
72
|
+
<path d="M 470 540 L 600 580" class="arrow"/>
|
|
73
|
+
|
|
74
|
+
<!-- Labels on arrows to actions -->
|
|
75
|
+
<text x="260" y="565" class="label">:buy</text>
|
|
76
|
+
<text x="400" y="575" class="label">:sell</text>
|
|
77
|
+
<text x="535" y="565" class="label">:hold</text>
|
|
78
|
+
</svg>
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 900" width="1200" height="900">
|
|
2
|
+
<defs>
|
|
3
|
+
<style>
|
|
4
|
+
.box { stroke: #ffffff; stroke-width: 3; }
|
|
5
|
+
.text { fill: #ffffff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 15px; font-weight: 600; text-anchor: middle; }
|
|
6
|
+
.small-text { fill: #ffffff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 13px; font-weight: 500; text-anchor: middle; }
|
|
7
|
+
.arrow { stroke: #ffffff; stroke-width: 2.5; fill: none; marker-end: url(#arrowhead); }
|
|
8
|
+
.layer-box { stroke: #ffffff; stroke-width: 2; fill: none; stroke-dasharray: 5,5; opacity: 0.6; }
|
|
9
|
+
.layer-title { fill: #ffffff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 18px; font-weight: 700; }
|
|
10
|
+
.diamond { stroke: #ffffff; stroke-width: 3; }
|
|
11
|
+
</style>
|
|
12
|
+
<marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
13
|
+
<polygon points="0 0, 10 3, 0 6" fill="#ffffff" />
|
|
14
|
+
</marker>
|
|
15
|
+
</defs>
|
|
16
|
+
|
|
17
|
+
<!-- Data Layer -->
|
|
18
|
+
<rect x="20" y="20" width="1160" height="140" rx="8" class="layer-box"/>
|
|
19
|
+
<text x="40" y="45" class="layer-title">Data Layer</text>
|
|
20
|
+
|
|
21
|
+
<rect x="80" y="70" width="200" height="60" rx="8" class="box" fill="#2E86DE"/>
|
|
22
|
+
<text x="180" y="97" class="text">Alpha Vantage</text>
|
|
23
|
+
<text x="180" y="115" class="text">API</text>
|
|
24
|
+
|
|
25
|
+
<rect x="350" y="70" width="200" height="60" rx="8" class="box" fill="#3867D6"/>
|
|
26
|
+
<text x="450" y="97" class="text">Yahoo</text>
|
|
27
|
+
<text x="450" y="115" class="text">Finance</text>
|
|
28
|
+
|
|
29
|
+
<rect x="620" y="70" width="200" height="60" rx="8" class="box" fill="#4B7BEC"/>
|
|
30
|
+
<text x="720" y="105" class="text">CSV Files</text>
|
|
31
|
+
|
|
32
|
+
<rect x="880" y="70" width="200" height="60" rx="8" class="box" fill="#5352ED"/>
|
|
33
|
+
<text x="980" y="105" class="text">Raw Data</text>
|
|
34
|
+
|
|
35
|
+
<!-- Core Layer -->
|
|
36
|
+
<rect x="20" y="180" width="1160" height="160" rx="8" class="layer-box"/>
|
|
37
|
+
<text x="40" y="205" class="layer-title">Core Layer</text>
|
|
38
|
+
|
|
39
|
+
<rect x="150" y="230" width="180" height="60" rx="8" class="box" fill="#10AC84"/>
|
|
40
|
+
<text x="240" y="265" class="text">SQA::Stock</text>
|
|
41
|
+
|
|
42
|
+
<rect x="400" y="230" width="200" height="60" rx="8" class="box" fill="#1DD1A1"/>
|
|
43
|
+
<text x="500" y="265" class="text">SQA::DataFrame</text>
|
|
44
|
+
|
|
45
|
+
<rect x="670" y="230" width="240" height="60" rx="8" class="box" fill="#00D2D3"/>
|
|
46
|
+
<text x="790" y="257" class="text">SQA::DataFrame</text>
|
|
47
|
+
<text x="790" y="275" class="text">::Data</text>
|
|
48
|
+
|
|
49
|
+
<rect x="980" y="230" width="180" height="60" rx="8" class="box" fill="#01A3A4"/>
|
|
50
|
+
<text x="1070" y="257" class="text">Price/Volume</text>
|
|
51
|
+
<text x="1070" y="275" class="text">Arrays</text>
|
|
52
|
+
|
|
53
|
+
<!-- Analysis Layer -->
|
|
54
|
+
<rect x="20" y="360" width="1160" height="140" rx="8" class="layer-box"/>
|
|
55
|
+
<text x="40" y="385" class="layer-title">Analysis Layer</text>
|
|
56
|
+
|
|
57
|
+
<rect x="350" y="410" width="240" height="60" rx="8" class="box" fill="#EE5A6F"/>
|
|
58
|
+
<text x="470" y="437" class="text">SQAI/TAI</text>
|
|
59
|
+
<text x="470" y="455" class="text">Indicators</text>
|
|
60
|
+
|
|
61
|
+
<rect x="680" y="410" width="200" height="60" rx="8" class="box" fill="#FF6B6B"/>
|
|
62
|
+
<text x="780" y="437" class="text">Technical</text>
|
|
63
|
+
<text x="780" y="455" class="text">Values</text>
|
|
64
|
+
|
|
65
|
+
<!-- Strategy Layer -->
|
|
66
|
+
<rect x="20" y="520" width="1160" height="220" rx="8" class="layer-box"/>
|
|
67
|
+
<text x="40" y="545" class="layer-title">Strategy Layer</text>
|
|
68
|
+
|
|
69
|
+
<rect x="80" y="570" width="200" height="60" rx="8" class="box" fill="#F368E0"/>
|
|
70
|
+
<text x="180" y="597" class="text">Strategy</text>
|
|
71
|
+
<text x="180" y="615" class="text">Vector</text>
|
|
72
|
+
|
|
73
|
+
<rect x="360" y="570" width="200" height="60" rx="8" class="box" fill="#E056FD"/>
|
|
74
|
+
<text x="460" y="597" class="text">Trading</text>
|
|
75
|
+
<text x="460" y="615" class="text">Strategies</text>
|
|
76
|
+
|
|
77
|
+
<!-- Diamond for Signal -->
|
|
78
|
+
<g transform="translate(720, 600)">
|
|
79
|
+
<polygon points="0,-40 60,0 0,40 -60,0" class="diamond" fill="#FD79A8"/>
|
|
80
|
+
<text x="0" y="5" class="text">Signal</text>
|
|
81
|
+
</g>
|
|
82
|
+
|
|
83
|
+
<rect x="860" y="570" width="120" height="60" rx="8" class="box" fill="#26DE81"/>
|
|
84
|
+
<text x="920" y="605" class="text">Buy</text>
|
|
85
|
+
|
|
86
|
+
<rect x="860" y="650" width="120" height="60" rx="8" class="box" fill="#FC5C65"/>
|
|
87
|
+
<text x="920" y="685" class="text">Sell</text>
|
|
88
|
+
|
|
89
|
+
<rect x="1010" y="610" width="120" height="60" rx="8" class="box" fill="#FED330"/>
|
|
90
|
+
<text x="1070" y="645" class="text">Hold</text>
|
|
91
|
+
|
|
92
|
+
<!-- Execution Layer -->
|
|
93
|
+
<rect x="20" y="760" width="1160" height="120" rx="8" class="layer-box"/>
|
|
94
|
+
<text x="40" y="785" class="layer-title">Execution Layer</text>
|
|
95
|
+
|
|
96
|
+
<rect x="250" y="805" width="180" height="60" rx="8" class="box" fill="#FF9F43"/>
|
|
97
|
+
<text x="340" y="840" class="text">Portfolio</text>
|
|
98
|
+
|
|
99
|
+
<rect x="510" y="805" width="180" height="60" rx="8" class="box" fill="#FFA502"/>
|
|
100
|
+
<text x="600" y="840" class="text">Backtest</text>
|
|
101
|
+
|
|
102
|
+
<rect x="770" y="805" width="200" height="60" rx="8" class="box" fill="#FF6348"/>
|
|
103
|
+
<text x="870" y="832" class="text">Performance</text>
|
|
104
|
+
<text x="870" y="850" class="text">Metrics</text>
|
|
105
|
+
|
|
106
|
+
<!-- Arrows -->
|
|
107
|
+
<!-- Data Layer -->
|
|
108
|
+
<path d="M 180 130 L 980 130 L 980 70" class="arrow"/>
|
|
109
|
+
<path d="M 450 130 L 980 130" class="arrow" stroke-dasharray="5,5"/>
|
|
110
|
+
<path d="M 720 130 L 980 130" class="arrow" stroke-dasharray="5,5"/>
|
|
111
|
+
|
|
112
|
+
<!-- To Core Layer -->
|
|
113
|
+
<path d="M 980 130 L 980 180 L 240 180 L 240 230" class="arrow"/>
|
|
114
|
+
|
|
115
|
+
<!-- Core Layer connections -->
|
|
116
|
+
<path d="M 330 260 L 400 260" class="arrow"/>
|
|
117
|
+
<path d="M 600 260 L 670 260" class="arrow"/>
|
|
118
|
+
<path d="M 910 260 L 980 260" class="arrow"/>
|
|
119
|
+
|
|
120
|
+
<!-- To Analysis Layer -->
|
|
121
|
+
<path d="M 1070 290 L 1070 340 L 470 340 L 470 410" class="arrow"/>
|
|
122
|
+
|
|
123
|
+
<!-- Analysis Layer -->
|
|
124
|
+
<path d="M 590 440 L 680 440" class="arrow"/>
|
|
125
|
+
|
|
126
|
+
<!-- To Strategy Layer -->
|
|
127
|
+
<path d="M 780 470 L 780 500 L 180 500 L 180 570" class="arrow"/>
|
|
128
|
+
|
|
129
|
+
<!-- Strategy Layer -->
|
|
130
|
+
<path d="M 280 600 L 360 600" class="arrow"/>
|
|
131
|
+
<path d="M 560 600 L 660 600" class="arrow"/>
|
|
132
|
+
<path d="M 780 600 L 860 600" class="arrow"/>
|
|
133
|
+
<path d="M 760 640 L 860 680" class="arrow"/>
|
|
134
|
+
<path d="M 780 600 L 860 600 L 1010 640" class="arrow"/>
|
|
135
|
+
|
|
136
|
+
<!-- To Execution Layer -->
|
|
137
|
+
<path d="M 460 630 L 460 760 L 340 760 L 340 805" class="arrow"/>
|
|
138
|
+
|
|
139
|
+
<!-- Execution Layer -->
|
|
140
|
+
<path d="M 430 835 L 510 835" class="arrow"/>
|
|
141
|
+
<path d="M 690 835 L 770 835" class="arrow"/>
|
|
142
|
+
|
|
143
|
+
<!-- Labels -->
|
|
144
|
+
<text x="510" y="125" class="small-text">Fetch</text>
|
|
145
|
+
<text x="665" y="125" class="small-text">Scrape</text>
|
|
146
|
+
<text x="815" y="125" class="small-text">Import</text>
|
|
147
|
+
<text x="345" y="255" class="small-text">Contains</text>
|
|
148
|
+
<text x="635" y="255" class="small-text">Metadata</text>
|
|
149
|
+
<text x="525" y="435" class="small-text">Calculate</text>
|
|
150
|
+
</svg>
|
data/docs/concepts/index.md
CHANGED
|
@@ -4,29 +4,259 @@ Understanding the fundamental building blocks of SQA.
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
SQA is built around several key concepts that work together to provide a comprehensive stock analysis framework
|
|
7
|
+
SQA is built around several key concepts that work together to provide a comprehensive stock analysis framework. This page explains the architecture and how all the pieces fit together.
|
|
8
8
|
|
|
9
|
-
|
|
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
|
|
9
|
+
## System Architecture
|
|
15
10
|
|
|
16
|
-
|
|
11
|
+

|
|
17
12
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
## Key Components
|
|
14
|
+
|
|
15
|
+
### 1. Stock Object (`SQA::Stock`)
|
|
16
|
+
|
|
17
|
+
The primary domain object representing a stock with all its associated data.
|
|
18
|
+
|
|
19
|
+
**Responsibilities:**
|
|
20
|
+
- Load and cache historical price data
|
|
21
|
+
- Fetch company overview information
|
|
22
|
+
- Manage data persistence (JSON metadata + CSV prices)
|
|
23
|
+
- Provide access to DataFrame for analysis
|
|
24
|
+
|
|
25
|
+
**Example:**
|
|
26
|
+
```ruby
|
|
27
|
+
stock = SQA::Stock.new(ticker: 'AAPL')
|
|
28
|
+
|
|
29
|
+
# Access data
|
|
30
|
+
stock.ticker # => "aapl"
|
|
31
|
+
stock.name # => "Apple Inc"
|
|
32
|
+
stock.exchange # => "NASDAQ"
|
|
33
|
+
stock.df # => SQA::DataFrame with price/volume
|
|
34
|
+
stock.overview # => Hash with company details
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. DataFrame (`SQA::DataFrame`)
|
|
38
|
+
|
|
39
|
+
High-performance wrapper around Polars for time series data manipulation.
|
|
40
|
+
|
|
41
|
+
**Key Features:**
|
|
42
|
+
- Rust-backed Polars engine (30x faster than pure Ruby)
|
|
43
|
+
- Columnar operations for efficiency
|
|
44
|
+
- CSV/JSON import/export
|
|
45
|
+
- Method delegation to Polars
|
|
46
|
+
|
|
47
|
+
**Standard Columns:**
|
|
48
|
+
| Column | Description |
|
|
49
|
+
|--------|-------------|
|
|
50
|
+
| `timestamp` | Date of trading day |
|
|
51
|
+
| `open_price` | Opening price |
|
|
52
|
+
| `high_price` | Highest price |
|
|
53
|
+
| `low_price` | Lowest price |
|
|
54
|
+
| `close_price` | Closing price |
|
|
55
|
+
| `adj_close_price` | Split/dividend adjusted price |
|
|
56
|
+
| `volume` | Trading volume |
|
|
57
|
+
|
|
58
|
+
**Example:**
|
|
59
|
+
```ruby
|
|
60
|
+
df = stock.df
|
|
61
|
+
|
|
62
|
+
# Column operations
|
|
63
|
+
prices = df["adj_close_price"].to_a
|
|
64
|
+
volumes = df["volume"].to_a
|
|
65
|
+
|
|
66
|
+
# Statistics (via Polars)
|
|
67
|
+
df.data["close_price"].mean
|
|
68
|
+
df.data["volume"].sum
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 3. Technical Indicators (`SQAI` / `SQA::TAI`)
|
|
72
|
+
|
|
73
|
+
150+ technical indicators provided by the `sqa-tai` gem, which wraps TA-Lib.
|
|
74
|
+
|
|
75
|
+
**Categories:**
|
|
76
|
+
- **Overlap Studies**: SMA, EMA, Bollinger Bands
|
|
77
|
+
- **Momentum**: RSI, MACD, Stochastic
|
|
78
|
+
- **Volume**: OBV, AD, ADOSC
|
|
79
|
+
- **Volatility**: ATR, NATR, True Range
|
|
80
|
+
- **Cycle**: Hilbert Transform indicators
|
|
81
|
+
- **Pattern**: Candlestick pattern recognition
|
|
82
|
+
|
|
83
|
+
**Example:**
|
|
84
|
+
```ruby
|
|
85
|
+
prices = stock.df["adj_close_price"].to_a
|
|
86
|
+
|
|
87
|
+
# Single-value indicators
|
|
88
|
+
sma = SQAI.sma(prices, period: 20)
|
|
89
|
+
rsi = SQAI.rsi(prices, period: 14)
|
|
90
|
+
|
|
91
|
+
# Multi-value indicators
|
|
92
|
+
macd, signal, histogram = SQAI.macd(prices)
|
|
93
|
+
upper, middle, lower = SQAI.bbands(prices, period: 20)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 4. Trading Strategies (`SQA::Strategy`)
|
|
97
|
+
|
|
98
|
+
Framework for creating and executing trading rules.
|
|
99
|
+
|
|
100
|
+
**Interface:**
|
|
101
|
+
```ruby
|
|
102
|
+
# All strategies implement this interface
|
|
103
|
+
class SQA::Strategy::MyStrategy
|
|
104
|
+
def self.trade(vector)
|
|
105
|
+
# Returns :buy, :sell, or :hold
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Built-in Strategies:**
|
|
111
|
+
- RSI, MACD, SMA, EMA
|
|
112
|
+
- Bollinger Bands, Stochastic
|
|
113
|
+
- Volume Breakout, Mean Reversion
|
|
114
|
+
- KBS (Knowledge-Based System)
|
|
115
|
+
- Consensus (aggregates multiple strategies)
|
|
116
|
+
|
|
117
|
+
**Example:**
|
|
118
|
+
```ruby
|
|
119
|
+
require 'ostruct'
|
|
120
|
+
|
|
121
|
+
vector = OpenStruct.new(
|
|
122
|
+
rsi: { trend: :over_sold, value: 28 },
|
|
123
|
+
prices: prices
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
signal = SQA::Strategy::RSI.trade(vector)
|
|
127
|
+
# => :buy
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 5. Portfolio (`SQA::Portfolio`)
|
|
131
|
+
|
|
132
|
+
Track positions, calculate P&L, and manage trades.
|
|
133
|
+
|
|
134
|
+
**Features:**
|
|
135
|
+
- Position tracking (shares per ticker)
|
|
136
|
+
- Commission handling
|
|
137
|
+
- Realized/unrealized P&L
|
|
138
|
+
- Trade history
|
|
139
|
+
|
|
140
|
+
**Example:**
|
|
141
|
+
```ruby
|
|
142
|
+
portfolio = SQA::Portfolio.new(initial_cash: 10_000, commission: 1.0)
|
|
143
|
+
portfolio.buy('AAPL', shares: 10, price: 150.0)
|
|
144
|
+
portfolio.sell('AAPL', shares: 5, price: 160.0)
|
|
145
|
+
|
|
146
|
+
portfolio.cash # Remaining cash
|
|
147
|
+
portfolio.positions # Current holdings
|
|
148
|
+
portfolio.trades # Trade history
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 6. Backtesting (`SQA::Backtest`)
|
|
152
|
+
|
|
153
|
+
Simulate strategies on historical data.
|
|
154
|
+
|
|
155
|
+
**Metrics Generated:**
|
|
156
|
+
- Total return, annualized return
|
|
157
|
+
- Sharpe ratio, Sortino ratio
|
|
158
|
+
- Maximum drawdown
|
|
159
|
+
- Win rate, profit factor
|
|
160
|
+
- Number of trades
|
|
161
|
+
|
|
162
|
+
**Example:**
|
|
163
|
+
```ruby
|
|
164
|
+
backtest = SQA::Backtest.new(
|
|
165
|
+
stock: stock,
|
|
166
|
+
strategy: SQA::Strategy::RSI,
|
|
167
|
+
initial_cash: 10_000
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
results = backtest.run
|
|
171
|
+
puts "Return: #{results.total_return}%"
|
|
172
|
+
puts "Sharpe: #{results.sharpe_ratio}"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Data Flow
|
|
176
|
+
|
|
177
|
+
Understanding how data flows through SQA:
|
|
178
|
+
|
|
179
|
+

|
|
180
|
+
|
|
181
|
+
## Data Ordering Convention
|
|
182
|
+
|
|
183
|
+
**Critical**: TA-Lib requires data in **ascending chronological order** (oldest first).
|
|
184
|
+
|
|
185
|
+
```ruby
|
|
186
|
+
# Correct order
|
|
187
|
+
prices = [100, 102, 105, 103, 108] # oldest → newest
|
|
188
|
+
# ^ ^
|
|
189
|
+
# index 0 index -1
|
|
190
|
+
|
|
191
|
+
# Access latest value
|
|
192
|
+
current_price = prices.last # or prices[-1]
|
|
193
|
+
|
|
194
|
+
# Calculate indicator
|
|
195
|
+
rsi = SQAI.rsi(prices, period: 14)
|
|
196
|
+
current_rsi = rsi.last # Most recent RSI value
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Configuration
|
|
200
|
+
|
|
201
|
+
SQA uses a hierarchical configuration system:
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
1. Default values (lowest priority)
|
|
205
|
+
2. Environment variables (SQA_* prefix)
|
|
206
|
+
3. Config file (~/.sqa.yml)
|
|
207
|
+
4. Runtime settings (highest priority)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Key Settings:**
|
|
211
|
+
```yaml
|
|
212
|
+
# ~/.sqa.yml
|
|
213
|
+
data_dir: ~/sqa_data
|
|
214
|
+
log_level: info
|
|
215
|
+
debug: false
|
|
216
|
+
verbose: false
|
|
217
|
+
lazy_update: false
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Environment Variables:**
|
|
221
|
+
```bash
|
|
222
|
+
export AV_API_KEY="your_alpha_vantage_key"
|
|
223
|
+
export SQA_DATA_DIR="~/my_data"
|
|
224
|
+
export SQA_DEBUG=true
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## File Storage
|
|
228
|
+
|
|
229
|
+
SQA stores data in the configured data directory (default: `~/sqa_data`):
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
~/sqa_data/
|
|
233
|
+
├── aapl.csv # Price/volume data
|
|
234
|
+
├── aapl.json # Stock metadata
|
|
235
|
+
├── msft.csv
|
|
236
|
+
├── msft.json
|
|
237
|
+
└── dumbstockapi-*.csv # Ticker validation data
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Module Structure
|
|
27
241
|
|
|
28
|
-
|
|
29
|
-
|
|
242
|
+
```
|
|
243
|
+
SQA
|
|
244
|
+
├── Stock # Primary domain object
|
|
245
|
+
├── DataFrame # Time series data wrapper
|
|
246
|
+
│ ├── Data # Stock metadata class
|
|
247
|
+
│ ├── AlphaVantage # Alpha Vantage adapter
|
|
248
|
+
│ └── YahooFinance # Yahoo Finance adapter
|
|
249
|
+
├── Strategy # Strategy framework
|
|
250
|
+
│ ├── RSI # RSI strategy
|
|
251
|
+
│ ├── MACD # MACD strategy
|
|
252
|
+
│ ├── BollingerBands # Bollinger Bands strategy
|
|
253
|
+
│ ├── KBS # Knowledge-based system
|
|
254
|
+
│ └── ... # Other strategies
|
|
255
|
+
├── Portfolio # Position tracking
|
|
256
|
+
├── Backtest # Historical simulation
|
|
257
|
+
├── Config # Configuration management
|
|
258
|
+
├── Ticker # Symbol validation
|
|
259
|
+
└── FPOP # Future Period analysis
|
|
30
260
|
```
|
|
31
261
|
|
|
32
262
|
## Learn More
|
|
@@ -57,4 +287,47 @@ graph TB
|
|
|
57
287
|
|
|
58
288
|
[:octicons-arrow-right-24: Strategies](../strategy.md)
|
|
59
289
|
|
|
290
|
+
- :material-briefcase:{ .lg .middle } __Portfolio__
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
Track positions, P&L, and trade history
|
|
295
|
+
|
|
296
|
+
[:octicons-arrow-right-24: Portfolio](../advanced/portfolio.md)
|
|
297
|
+
|
|
298
|
+
- :material-chart-timeline:{ .lg .middle } __Backtesting__
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
Test strategies on historical data
|
|
303
|
+
|
|
304
|
+
[:octicons-arrow-right-24: Backtesting](../advanced/backtesting.md)
|
|
305
|
+
|
|
306
|
+
- :material-cog:{ .lg .middle } __Configuration__
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
Set up data directories and API keys
|
|
311
|
+
|
|
312
|
+
[:octicons-arrow-right-24: Installation](../getting-started/installation.md)
|
|
313
|
+
|
|
60
314
|
</div>
|
|
315
|
+
|
|
316
|
+
## Design Principles
|
|
317
|
+
|
|
318
|
+
### 1. Plugin Architecture
|
|
319
|
+
Strategies are pluggable modules that follow a common interface. Add new strategies without modifying core code.
|
|
320
|
+
|
|
321
|
+
### 2. Data Source Abstraction
|
|
322
|
+
Multiple data providers (Alpha Vantage, Yahoo Finance, CSV) share a common interface. Easy to add new sources.
|
|
323
|
+
|
|
324
|
+
### 3. Performance First
|
|
325
|
+
Polars DataFrame operations are vectorized and Rust-backed. Avoid Ruby loops over data.
|
|
326
|
+
|
|
327
|
+
### 4. Educational Focus
|
|
328
|
+
Clear documentation, transparent algorithms, and honest risk disclaimers.
|
|
329
|
+
|
|
330
|
+
### 5. Separation of Concerns
|
|
331
|
+
- Data fetching is separate from analysis
|
|
332
|
+
- Indicators are separate from strategies
|
|
333
|
+
- Strategies are separate from execution
|