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,779 @@
|
|
|
1
|
+
# 📦 SQA::DataFrame
|
|
2
|
+
|
|
3
|
+
!!! note "Description"
|
|
4
|
+
High-performance DataFrame wrapper around Polars for time series data manipulation.
|
|
5
|
+
Provides convenience methods for stock market data while leveraging Polars' Rust-backed
|
|
6
|
+
performance for vectorized operations.
|
|
7
|
+
|
|
8
|
+
!!! abstract "Source Information"
|
|
9
|
+
**Defined in:** [`lib/sqa/data_frame.rb:28`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L28)
|
|
10
|
+
|
|
11
|
+
**Inherits from:** `Object`
|
|
12
|
+
|
|
13
|
+
## 🏭 Class Methods
|
|
14
|
+
|
|
15
|
+
### `.is_date?(value)`
|
|
16
|
+
|
|
17
|
+
Checks if a value appears to be a date string.
|
|
18
|
+
|
|
19
|
+
!!! info "Parameters"
|
|
20
|
+
|
|
21
|
+
| Name | Type | Description |
|
|
22
|
+
|------|------|-------------|
|
|
23
|
+
| `value` | `Object` | Value to check |
|
|
24
|
+
!!! success "Returns"
|
|
25
|
+
|
|
26
|
+
**Type:** `Boolean`
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
true if value matches YYYY-MM-DD format
|
|
31
|
+
|
|
32
|
+
??? info "Source Location"
|
|
33
|
+
[`lib/sqa/data_frame.rb:246`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L246)
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
### `.load(source:, transformers: = {}, mapping: = {})`
|
|
38
|
+
|
|
39
|
+
Load a DataFrame from a file source
|
|
40
|
+
This is the primary method for loading persisted DataFrames
|
|
41
|
+
|
|
42
|
+
Note: For cached CSV files, transformers and mapping should typically be empty
|
|
43
|
+
since transformations were already applied when the data was first fetched.
|
|
44
|
+
We only apply them if the CSV has old-format column names that need migration.
|
|
45
|
+
|
|
46
|
+
!!! info "Parameters"
|
|
47
|
+
|
|
48
|
+
| Name | Type | Description |
|
|
49
|
+
|------|------|-------------|
|
|
50
|
+
| `source` | `String, Pathname` | Path to CSV file |
|
|
51
|
+
| `transformers` | `Hash` | Column transformations to apply (usually not needed for cached data) |
|
|
52
|
+
| `mapping` | `Hash` | Column name mappings (usually not needed for cached data) |
|
|
53
|
+
!!! success "Returns"
|
|
54
|
+
|
|
55
|
+
**Type:** `SQA::DataFrame`
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
Loaded DataFrame
|
|
60
|
+
|
|
61
|
+
??? info "Source Location"
|
|
62
|
+
[`lib/sqa/data_frame.rb:283`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L283)
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### `.from_aofh(aofh, mapping: = {}, transformers: = {})`
|
|
67
|
+
|
|
68
|
+
Creates a DataFrame from an array of hashes.
|
|
69
|
+
|
|
70
|
+
!!! info "Parameters"
|
|
71
|
+
|
|
72
|
+
| Name | Type | Description |
|
|
73
|
+
|------|------|-------------|
|
|
74
|
+
| `aofh` | `Array<Hash>` | Array of hash records |
|
|
75
|
+
| `mapping` | `Hash` | Column name mappings to apply |
|
|
76
|
+
| `transformers` | `Hash` | Column transformers to apply |
|
|
77
|
+
!!! success "Returns"
|
|
78
|
+
|
|
79
|
+
**Type:** `SQA::DataFrame`
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
New DataFrame instance
|
|
84
|
+
!!! example "Usage Examples"
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
data = [{ "date" => "2024-01-01", "price" => 100.0 }]
|
|
88
|
+
df = SQA::DataFrame.from_aofh(data)
|
|
89
|
+
```
|
|
90
|
+
??? info "Source Location"
|
|
91
|
+
[`lib/sqa/data_frame.rb:302`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L302)
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
### `.from_csv_file(source, mapping: = {}, transformers: = {})`
|
|
96
|
+
|
|
97
|
+
Creates a DataFrame from a CSV file.
|
|
98
|
+
|
|
99
|
+
!!! info "Parameters"
|
|
100
|
+
|
|
101
|
+
| Name | Type | Description |
|
|
102
|
+
|------|------|-------------|
|
|
103
|
+
| `source` | `String, Pathname` | Path to CSV file |
|
|
104
|
+
| `mapping` | `Hash` | Column name mappings to apply |
|
|
105
|
+
| `transformers` | `Hash` | Column transformers to apply |
|
|
106
|
+
!!! success "Returns"
|
|
107
|
+
|
|
108
|
+
**Type:** `SQA::DataFrame`
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
New DataFrame instance
|
|
113
|
+
|
|
114
|
+
??? info "Source Location"
|
|
115
|
+
[`lib/sqa/data_frame.rb:324`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L324)
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
### `.from_json_file(source, mapping: = {}, transformers: = {})`
|
|
120
|
+
|
|
121
|
+
Creates a DataFrame from a JSON file.
|
|
122
|
+
|
|
123
|
+
!!! info "Parameters"
|
|
124
|
+
|
|
125
|
+
| Name | Type | Description |
|
|
126
|
+
|------|------|-------------|
|
|
127
|
+
| `source` | `String, Pathname` | Path to JSON file containing array of objects |
|
|
128
|
+
| `mapping` | `Hash` | Column name mappings to apply |
|
|
129
|
+
| `transformers` | `Hash` | Column transformers to apply |
|
|
130
|
+
!!! success "Returns"
|
|
131
|
+
|
|
132
|
+
**Type:** `SQA::DataFrame`
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
New DataFrame instance
|
|
137
|
+
|
|
138
|
+
??? info "Source Location"
|
|
139
|
+
[`lib/sqa/data_frame.rb:335`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L335)
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### `.generate_mapping(keys)`
|
|
144
|
+
|
|
145
|
+
Generates a mapping of original keys to underscored keys.
|
|
146
|
+
|
|
147
|
+
!!! info "Parameters"
|
|
148
|
+
|
|
149
|
+
| Name | Type | Description |
|
|
150
|
+
|------|------|-------------|
|
|
151
|
+
| `keys` | `Array<String>` | Original key names |
|
|
152
|
+
!!! success "Returns"
|
|
153
|
+
|
|
154
|
+
**Type:** `Hash{String => Symbol}`
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
Mapping from original to underscored keys
|
|
159
|
+
|
|
160
|
+
??? info "Source Location"
|
|
161
|
+
[`lib/sqa/data_frame.rb:344`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L344)
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### `.underscore_key(key)`
|
|
166
|
+
|
|
167
|
+
Converts a key string to underscored snake_case format.
|
|
168
|
+
|
|
169
|
+
!!! info "Parameters"
|
|
170
|
+
|
|
171
|
+
| Name | Type | Description |
|
|
172
|
+
|------|------|-------------|
|
|
173
|
+
| `key` | `String` | Key to convert |
|
|
174
|
+
!!! success "Returns"
|
|
175
|
+
|
|
176
|
+
**Type:** `Symbol`
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
Underscored key as symbol
|
|
181
|
+
!!! example "Usage Examples"
|
|
182
|
+
|
|
183
|
+
```ruby
|
|
184
|
+
underscore_key("closePrice") # => :close_price
|
|
185
|
+
underscore_key("Close Price") # => :close_price
|
|
186
|
+
```
|
|
187
|
+
??? info "Source Location"
|
|
188
|
+
[`lib/sqa/data_frame.rb:359`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L359)
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
### `.sanitize_key()`
|
|
193
|
+
|
|
194
|
+
Converts a key string to underscored snake_case format.
|
|
195
|
+
|
|
196
|
+
!!! info "Parameters"
|
|
197
|
+
|
|
198
|
+
| Name | Type | Description |
|
|
199
|
+
|------|------|-------------|
|
|
200
|
+
| `key` | `String` | Key to convert |
|
|
201
|
+
!!! success "Returns"
|
|
202
|
+
|
|
203
|
+
**Type:** `Symbol`
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
Underscored key as symbol
|
|
208
|
+
!!! example "Usage Examples"
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
underscore_key("closePrice") # => :close_price
|
|
212
|
+
underscore_key("Close Price") # => :close_price
|
|
213
|
+
```
|
|
214
|
+
??? info "Source Location"
|
|
215
|
+
[`lib/sqa/data_frame.rb:371`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L371)
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
### `.normalize_keys(hash, adapter_mapping: = {})`
|
|
220
|
+
|
|
221
|
+
Normalizes all keys in a hash to snake_case format.
|
|
222
|
+
|
|
223
|
+
!!! info "Parameters"
|
|
224
|
+
|
|
225
|
+
| Name | Type | Description |
|
|
226
|
+
|------|------|-------------|
|
|
227
|
+
| `hash` | `Hash` | Hash with keys to normalize |
|
|
228
|
+
| `adapter_mapping` | `Hash` | Optional pre-mapping to apply first |
|
|
229
|
+
!!! success "Returns"
|
|
230
|
+
|
|
231
|
+
**Type:** `Hash`
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
Hash with normalized keys
|
|
236
|
+
|
|
237
|
+
??? info "Source Location"
|
|
238
|
+
[`lib/sqa/data_frame.rb:378`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L378)
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
### `.rename(hash, mapping)`
|
|
243
|
+
|
|
244
|
+
Renames keys in a hash according to a mapping.
|
|
245
|
+
|
|
246
|
+
!!! info "Parameters"
|
|
247
|
+
|
|
248
|
+
| Name | Type | Description |
|
|
249
|
+
|------|------|-------------|
|
|
250
|
+
| `hash` | `Hash` | Hash to modify |
|
|
251
|
+
| `mapping` | `Hash` | Old key to new key mapping |
|
|
252
|
+
!!! success "Returns"
|
|
253
|
+
|
|
254
|
+
**Type:** `Hash`
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
Modified hash
|
|
259
|
+
|
|
260
|
+
??? info "Source Location"
|
|
261
|
+
[`lib/sqa/data_frame.rb:389`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L389)
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
### `.aofh_to_hofa(aofh, mapping: = {}, transformers: = {})`
|
|
266
|
+
|
|
267
|
+
Converts array of hashes to hash of arrays format.
|
|
268
|
+
|
|
269
|
+
!!! info "Parameters"
|
|
270
|
+
|
|
271
|
+
| Name | Type | Description |
|
|
272
|
+
|------|------|-------------|
|
|
273
|
+
| `aofh` | `Array<Hash>` | Array of hash records |
|
|
274
|
+
| `mapping` | `Hash` | Column name mappings (unused, for API compatibility) |
|
|
275
|
+
| `transformers` | `Hash` | Column transformers (unused, for API compatibility) |
|
|
276
|
+
!!! success "Returns"
|
|
277
|
+
|
|
278
|
+
**Type:** `Hash{String => Array}`
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
Hash with column names as keys and arrays as values
|
|
283
|
+
|
|
284
|
+
??? info "Source Location"
|
|
285
|
+
[`lib/sqa/data_frame.rb:400`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L400)
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## 🔨 Instance Methods
|
|
290
|
+
|
|
291
|
+
### `#data()`
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
!!! success "Returns"
|
|
295
|
+
|
|
296
|
+
**Type:** `Polars::DataFrame`
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
The underlying Polars DataFrame
|
|
301
|
+
|
|
302
|
+
??? info "Source Location"
|
|
303
|
+
[`lib/sqa/data_frame.rb:33`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L33)
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
### `#data=(value)`
|
|
308
|
+
|
|
309
|
+
Sets the attribute data
|
|
310
|
+
|
|
311
|
+
!!! info "Parameters"
|
|
312
|
+
|
|
313
|
+
| Name | Type | Description |
|
|
314
|
+
|------|------|-------------|
|
|
315
|
+
| `value` | `Any` | the value to set the attribute data to. |
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
??? info "Source Location"
|
|
319
|
+
[`lib/sqa/data_frame.rb:33`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L33)
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
### `#initialize(raw_data = nil, mapping: = {}, transformers: = {})`
|
|
324
|
+
|
|
325
|
+
Creates a new DataFrame instance.
|
|
326
|
+
|
|
327
|
+
!!! info "Parameters"
|
|
328
|
+
|
|
329
|
+
| Name | Type | Description |
|
|
330
|
+
|------|------|-------------|
|
|
331
|
+
| `raw_data` | `Hash, Array, Polars::DataFrame, nil` | Initial data for the DataFrame |
|
|
332
|
+
| `mapping` | `Hash` | Column name mappings to apply (old_name => new_name) |
|
|
333
|
+
| `transformers` | `Hash` | Column transformers to apply (column => lambda) |
|
|
334
|
+
!!! success "Returns"
|
|
335
|
+
|
|
336
|
+
**Type:** `DataFrame`
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
a new instance of DataFrame
|
|
341
|
+
!!! example "Usage Examples"
|
|
342
|
+
|
|
343
|
+
```ruby
|
|
344
|
+
df = SQA::DataFrame.new(data, mapping: { "Close" => "close_price" })
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
```ruby
|
|
348
|
+
df = SQA::DataFrame.new(data, transformers: { "price" => ->(v) { v.to_f } })
|
|
349
|
+
```
|
|
350
|
+
??? info "Source Location"
|
|
351
|
+
[`lib/sqa/data_frame.rb:47`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L47)
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
### `#apply_transformers!(transformers)`
|
|
356
|
+
|
|
357
|
+
Applies transformer functions to specified columns in place.
|
|
358
|
+
|
|
359
|
+
!!! info "Parameters"
|
|
360
|
+
|
|
361
|
+
| Name | Type | Description |
|
|
362
|
+
|------|------|-------------|
|
|
363
|
+
| `transformers` | `Hash{String, Symbol => Proc}` | Column name to transformer mapping |
|
|
364
|
+
!!! success "Returns"
|
|
365
|
+
|
|
366
|
+
**Type:** `void`
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
!!! example "Usage Examples"
|
|
370
|
+
|
|
371
|
+
```ruby
|
|
372
|
+
df.apply_transformers!({ "price" => ->(v) { v.to_f }, "volume" => ->(v) { v.to_i } })
|
|
373
|
+
```
|
|
374
|
+
??? info "Source Location"
|
|
375
|
+
[`lib/sqa/data_frame.rb:65`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L65)
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
### `#rename_columns!(mapping)`
|
|
380
|
+
|
|
381
|
+
Renames columns according to the provided mapping in place.
|
|
382
|
+
|
|
383
|
+
!!! info "Parameters"
|
|
384
|
+
|
|
385
|
+
| Name | Type | Description |
|
|
386
|
+
|------|------|-------------|
|
|
387
|
+
| `mapping` | `Hash{String, Symbol => String}` | Old column name to new column name mapping |
|
|
388
|
+
!!! success "Returns"
|
|
389
|
+
|
|
390
|
+
**Type:** `void`
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
!!! example "Usage Examples"
|
|
394
|
+
|
|
395
|
+
```ruby
|
|
396
|
+
df.rename_columns!({ "open" => "open_price", "close" => "close_price" })
|
|
397
|
+
```
|
|
398
|
+
??? info "Source Location"
|
|
399
|
+
[`lib/sqa/data_frame.rb:82`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L82)
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
### `#append!(other_df)`
|
|
404
|
+
|
|
405
|
+
Appends another DataFrame to this one in place.
|
|
406
|
+
|
|
407
|
+
!!! info "Parameters"
|
|
408
|
+
|
|
409
|
+
| Name | Type | Description |
|
|
410
|
+
|------|------|-------------|
|
|
411
|
+
| `other_df` | `SQA::DataFrame` | DataFrame to append |
|
|
412
|
+
!!! success "Returns"
|
|
413
|
+
|
|
414
|
+
**Type:** `void`
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
!!! example "Usage Examples"
|
|
418
|
+
|
|
419
|
+
```ruby
|
|
420
|
+
df1.append!(df2)
|
|
421
|
+
```
|
|
422
|
+
??? info "Source Location"
|
|
423
|
+
[`lib/sqa/data_frame.rb:107`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L107)
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
### `#concat!()`
|
|
428
|
+
|
|
429
|
+
Appends another DataFrame to this one in place.
|
|
430
|
+
|
|
431
|
+
!!! info "Parameters"
|
|
432
|
+
|
|
433
|
+
| Name | Type | Description |
|
|
434
|
+
|------|------|-------------|
|
|
435
|
+
| `other_df` | `SQA::DataFrame` | DataFrame to append |
|
|
436
|
+
!!! success "Returns"
|
|
437
|
+
|
|
438
|
+
**Type:** `void`
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
!!! example "Usage Examples"
|
|
442
|
+
|
|
443
|
+
```ruby
|
|
444
|
+
df1.append!(df2)
|
|
445
|
+
```
|
|
446
|
+
??? info "Source Location"
|
|
447
|
+
[`lib/sqa/data_frame.rb:124`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L124)
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
### `#concat_and_deduplicate!(other_df, sort_column: = "timestamp", descending: = false)`
|
|
452
|
+
|
|
453
|
+
Concatenate another DataFrame, remove duplicates, and sort
|
|
454
|
+
This is the preferred method for updating CSV data to prevent duplicates
|
|
455
|
+
|
|
456
|
+
NOTE: TA-Lib requires data in ascending (oldest-first) order. Using descending: true
|
|
457
|
+
will produce a warning and force ascending order to prevent silent calculation errors.
|
|
458
|
+
|
|
459
|
+
!!! info "Parameters"
|
|
460
|
+
|
|
461
|
+
| Name | Type | Description |
|
|
462
|
+
|------|------|-------------|
|
|
463
|
+
| `other_df` | `SQA::DataFrame` | DataFrame to append |
|
|
464
|
+
| `sort_column` | `String` | Column to use for deduplication and sorting (default: "timestamp") |
|
|
465
|
+
| `descending` | `Boolean` | Sort order - false for ascending (oldest first, TA-Lib compatible), true for descending |
|
|
466
|
+
|
|
467
|
+
!!! example "Usage Examples"
|
|
468
|
+
|
|
469
|
+
```ruby
|
|
470
|
+
stock = SQA::Stock.new(ticker: 'AAPL')
|
|
471
|
+
df = stock.df
|
|
472
|
+
df.size # => 252
|
|
473
|
+
|
|
474
|
+
# Fetch recent data (may have overlapping dates)
|
|
475
|
+
new_df = SQA::DataFrame::AlphaVantage.recent('AAPL', from_date: Date.today - 7)
|
|
476
|
+
df.concat_and_deduplicate!(new_df)
|
|
477
|
+
# Duplicates removed, data sorted ascending (oldest first)
|
|
478
|
+
df.size # => 255 (only 3 new unique dates added)
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
```ruby
|
|
482
|
+
df.concat_and_deduplicate!(new_df) # Sorted ascending automatically
|
|
483
|
+
prices = df["adj_close_price"].to_a
|
|
484
|
+
rsi = SQAI.rsi(prices, period: 14) # Works correctly with ascending data
|
|
485
|
+
```
|
|
486
|
+
??? info "Source Location"
|
|
487
|
+
[`lib/sqa/data_frame.rb:135`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L135)
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
### `#columns()`
|
|
492
|
+
|
|
493
|
+
Returns the column names of the DataFrame.
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
!!! success "Returns"
|
|
497
|
+
|
|
498
|
+
**Type:** `Array<String>`
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
List of column names
|
|
503
|
+
|
|
504
|
+
??? info "Source Location"
|
|
505
|
+
[`lib/sqa/data_frame.rb:159`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L159)
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
### `#keys()`
|
|
510
|
+
|
|
511
|
+
Returns the column names of the DataFrame.
|
|
512
|
+
Alias for {#columns}.
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
!!! success "Returns"
|
|
516
|
+
|
|
517
|
+
**Type:** `Array<String>`
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
List of column names
|
|
522
|
+
|
|
523
|
+
??? info "Source Location"
|
|
524
|
+
[`lib/sqa/data_frame.rb:167`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L167)
|
|
525
|
+
|
|
526
|
+
---
|
|
527
|
+
|
|
528
|
+
### `#vectors()`
|
|
529
|
+
|
|
530
|
+
Returns the column names of the DataFrame.
|
|
531
|
+
Alias for {#columns}.
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
!!! success "Returns"
|
|
535
|
+
|
|
536
|
+
**Type:** `Array<String>`
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
List of column names
|
|
541
|
+
|
|
542
|
+
??? info "Source Location"
|
|
543
|
+
[`lib/sqa/data_frame.rb:170`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L170)
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
### `#to_h()`
|
|
548
|
+
|
|
549
|
+
Converts the DataFrame to a Ruby Hash.
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
!!! success "Returns"
|
|
553
|
+
|
|
554
|
+
**Type:** `Hash{Symbol => Array}`
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
Hash with column names as keys and column data as arrays
|
|
559
|
+
!!! example "Usage Examples"
|
|
560
|
+
|
|
561
|
+
```ruby
|
|
562
|
+
df.to_h # => { timestamp: ["2024-01-01", ...], close_price: [100.0, ...] }
|
|
563
|
+
```
|
|
564
|
+
??? info "Source Location"
|
|
565
|
+
[`lib/sqa/data_frame.rb:179`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L179)
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
569
|
+
### `#to_csv(path_to_file)`
|
|
570
|
+
|
|
571
|
+
Writes the DataFrame to a CSV file.
|
|
572
|
+
|
|
573
|
+
!!! info "Parameters"
|
|
574
|
+
|
|
575
|
+
| Name | Type | Description |
|
|
576
|
+
|------|------|-------------|
|
|
577
|
+
| `path_to_file` | `String, Pathname` | Path to output CSV file |
|
|
578
|
+
!!! success "Returns"
|
|
579
|
+
|
|
580
|
+
**Type:** `void`
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
!!! example "Usage Examples"
|
|
584
|
+
|
|
585
|
+
```ruby
|
|
586
|
+
stock = SQA::Stock.new(ticker: 'AAPL')
|
|
587
|
+
stock.df.to_csv('aapl_prices.csv')
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
```ruby
|
|
591
|
+
df.to_csv(Pathname.new('data/exports/prices.csv'))
|
|
592
|
+
```
|
|
593
|
+
??? info "Source Location"
|
|
594
|
+
[`lib/sqa/data_frame.rb:187`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L187)
|
|
595
|
+
|
|
596
|
+
---
|
|
597
|
+
|
|
598
|
+
### `#size()`
|
|
599
|
+
|
|
600
|
+
Returns the number of rows in the DataFrame.
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
!!! success "Returns"
|
|
604
|
+
|
|
605
|
+
**Type:** `Integer`
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
Row count
|
|
610
|
+
|
|
611
|
+
??? info "Source Location"
|
|
612
|
+
[`lib/sqa/data_frame.rb:194`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L194)
|
|
613
|
+
|
|
614
|
+
---
|
|
615
|
+
|
|
616
|
+
### `#nrows()`
|
|
617
|
+
|
|
618
|
+
Returns the number of rows in the DataFrame.
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
!!! success "Returns"
|
|
622
|
+
|
|
623
|
+
**Type:** `Integer`
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
Row count
|
|
628
|
+
|
|
629
|
+
??? info "Source Location"
|
|
630
|
+
[`lib/sqa/data_frame.rb:197`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L197)
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
### `#length()`
|
|
635
|
+
|
|
636
|
+
Returns the number of rows in the DataFrame.
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
!!! success "Returns"
|
|
640
|
+
|
|
641
|
+
**Type:** `Integer`
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
Row count
|
|
646
|
+
|
|
647
|
+
??? info "Source Location"
|
|
648
|
+
[`lib/sqa/data_frame.rb:198`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L198)
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
### `#ncols()`
|
|
653
|
+
|
|
654
|
+
Returns the number of columns in the DataFrame.
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
!!! success "Returns"
|
|
658
|
+
|
|
659
|
+
**Type:** `Integer`
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
Column count
|
|
664
|
+
|
|
665
|
+
??? info "Source Location"
|
|
666
|
+
[`lib/sqa/data_frame.rb:203`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L203)
|
|
667
|
+
|
|
668
|
+
---
|
|
669
|
+
|
|
670
|
+
### `#fpl(column: = 'adj_close_price', fpop: = 14)`
|
|
671
|
+
|
|
672
|
+
FPL Analysis - Calculate Future Period Loss/Profit
|
|
673
|
+
|
|
674
|
+
!!! info "Parameters"
|
|
675
|
+
|
|
676
|
+
| Name | Type | Description |
|
|
677
|
+
|------|------|-------------|
|
|
678
|
+
| `column` | `String, Symbol` | Column name containing prices (default: "adj_close_price") |
|
|
679
|
+
| `fpop` | `Integer` | Future Period of Performance (days to look ahead) |
|
|
680
|
+
!!! success "Returns"
|
|
681
|
+
|
|
682
|
+
**Type:** `Array<Array<Float, Float>>`
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
Array of [min_delta, max_delta] pairs
|
|
687
|
+
!!! example "Usage Examples"
|
|
688
|
+
|
|
689
|
+
```ruby
|
|
690
|
+
stock = SQA::Stock.new(ticker: 'AAPL')
|
|
691
|
+
fpl_data = stock.df.fpl(fpop: 10)
|
|
692
|
+
```
|
|
693
|
+
??? info "Source Location"
|
|
694
|
+
[`lib/sqa/data_frame.rb:218`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L218)
|
|
695
|
+
|
|
696
|
+
---
|
|
697
|
+
|
|
698
|
+
### `#fpl_analysis(column: = 'adj_close_price', fpop: = 14)`
|
|
699
|
+
|
|
700
|
+
FPL Analysis with risk metrics and classification
|
|
701
|
+
|
|
702
|
+
!!! info "Parameters"
|
|
703
|
+
|
|
704
|
+
| Name | Type | Description |
|
|
705
|
+
|------|------|-------------|
|
|
706
|
+
| `column` | `String, Symbol` | Column name containing prices (default: "adj_close_price") |
|
|
707
|
+
| `fpop` | `Integer` | Future Period of Performance |
|
|
708
|
+
!!! success "Returns"
|
|
709
|
+
|
|
710
|
+
**Type:** `Array<Hash>`
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
Array of analysis hashes
|
|
715
|
+
!!! example "Usage Examples"
|
|
716
|
+
|
|
717
|
+
```ruby
|
|
718
|
+
analysis = stock.df.fpl_analysis(fpop: 10)
|
|
719
|
+
analysis.first[:direction] # => :UP, :DOWN, :UNCERTAIN, or :FLAT
|
|
720
|
+
analysis.first[:magnitude] # => Average expected movement percentage
|
|
721
|
+
analysis.first[:risk] # => Volatility range
|
|
722
|
+
```
|
|
723
|
+
??? info "Source Location"
|
|
724
|
+
[`lib/sqa/data_frame.rb:236`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L236)
|
|
725
|
+
|
|
726
|
+
---
|
|
727
|
+
|
|
728
|
+
### `#method_missing(method_name, *args, &block)`
|
|
729
|
+
|
|
730
|
+
Delegates unknown methods to the underlying Polars DataFrame.
|
|
731
|
+
This allows direct access to Polars methods like filter, select, etc.
|
|
732
|
+
|
|
733
|
+
!!! info "Parameters"
|
|
734
|
+
|
|
735
|
+
| Name | Type | Description |
|
|
736
|
+
|------|------|-------------|
|
|
737
|
+
| `method_name` | `Symbol` | Method name being called |
|
|
738
|
+
| `args` | `Array` | Method arguments |
|
|
739
|
+
| `block` | `Proc` | Optional block |
|
|
740
|
+
!!! success "Returns"
|
|
741
|
+
|
|
742
|
+
**Type:** `Object`
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
Result from Polars DataFrame method
|
|
747
|
+
|
|
748
|
+
??? info "Source Location"
|
|
749
|
+
[`lib/sqa/data_frame.rb:257`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L257)
|
|
750
|
+
|
|
751
|
+
---
|
|
752
|
+
|
|
753
|
+
### `#respond_to_missing?(method_name, include_private = false)`
|
|
754
|
+
|
|
755
|
+
Checks if the DataFrame responds to a method.
|
|
756
|
+
|
|
757
|
+
!!! info "Parameters"
|
|
758
|
+
|
|
759
|
+
| Name | Type | Description |
|
|
760
|
+
|------|------|-------------|
|
|
761
|
+
| `method_name` | `Symbol` | Method name to check |
|
|
762
|
+
| `include_private` | `Boolean` | Include private methods |
|
|
763
|
+
!!! success "Returns"
|
|
764
|
+
|
|
765
|
+
**Type:** `Boolean`
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
true if method is available
|
|
770
|
+
|
|
771
|
+
??? info "Source Location"
|
|
772
|
+
[`lib/sqa/data_frame.rb:267`](https://github.com/madbomber/sqa/blob/main/lib/sqa/data_frame.rb#L267)
|
|
773
|
+
|
|
774
|
+
---
|
|
775
|
+
|
|
776
|
+
## 📝 Attributes
|
|
777
|
+
|
|
778
|
+
### 🔄 `data` <small>read/write</small>
|
|
779
|
+
|