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,512 @@
|
|
|
1
|
+
# 📦 SQA::Portfolio
|
|
2
|
+
|
|
3
|
+
!!! abstract "Source Information"
|
|
4
|
+
**Defined in:** [`lib/sqa/portfolio.rb:7`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L7)
|
|
5
|
+
|
|
6
|
+
**Inherits from:** `Object`
|
|
7
|
+
|
|
8
|
+
## 🏭 Class Methods
|
|
9
|
+
|
|
10
|
+
### `.load_from_csv(filename)`
|
|
11
|
+
|
|
12
|
+
Load portfolio from CSV file
|
|
13
|
+
|
|
14
|
+
!!! info "Parameters"
|
|
15
|
+
|
|
16
|
+
| Name | Type | Description |
|
|
17
|
+
|------|------|-------------|
|
|
18
|
+
| `filename` | `String` | Path to CSV file |
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
??? info "Source Location"
|
|
22
|
+
[`lib/sqa/portfolio.rb:236`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L236)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 🔨 Instance Methods
|
|
27
|
+
|
|
28
|
+
### `#positions()`
|
|
29
|
+
|
|
30
|
+
Returns the value of attribute positions.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
??? info "Source Location"
|
|
36
|
+
[`lib/sqa/portfolio.rb:8`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L8)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
### `#positions=(value)`
|
|
41
|
+
|
|
42
|
+
Sets the attribute positions
|
|
43
|
+
|
|
44
|
+
!!! info "Parameters"
|
|
45
|
+
|
|
46
|
+
| Name | Type | Description |
|
|
47
|
+
|------|------|-------------|
|
|
48
|
+
| `value` | `Any` | the value to set the attribute positions to. |
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
??? info "Source Location"
|
|
52
|
+
[`lib/sqa/portfolio.rb:8`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L8)
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### `#trades()`
|
|
57
|
+
|
|
58
|
+
Returns the value of attribute trades.
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
??? info "Source Location"
|
|
64
|
+
[`lib/sqa/portfolio.rb:8`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L8)
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### `#trades=(value)`
|
|
69
|
+
|
|
70
|
+
Sets the attribute trades
|
|
71
|
+
|
|
72
|
+
!!! info "Parameters"
|
|
73
|
+
|
|
74
|
+
| Name | Type | Description |
|
|
75
|
+
|------|------|-------------|
|
|
76
|
+
| `value` | `Any` | the value to set the attribute trades to. |
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
??? info "Source Location"
|
|
80
|
+
[`lib/sqa/portfolio.rb:8`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L8)
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### `#cash()`
|
|
85
|
+
|
|
86
|
+
Returns the value of attribute cash.
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
??? info "Source Location"
|
|
92
|
+
[`lib/sqa/portfolio.rb:8`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L8)
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### `#cash=(value)`
|
|
97
|
+
|
|
98
|
+
Sets the attribute cash
|
|
99
|
+
|
|
100
|
+
!!! info "Parameters"
|
|
101
|
+
|
|
102
|
+
| Name | Type | Description |
|
|
103
|
+
|------|------|-------------|
|
|
104
|
+
| `value` | `Any` | the value to set the attribute cash to. |
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
??? info "Source Location"
|
|
108
|
+
[`lib/sqa/portfolio.rb:8`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L8)
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### `#initial_cash()`
|
|
113
|
+
|
|
114
|
+
Returns the value of attribute initial_cash.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
??? info "Source Location"
|
|
120
|
+
[`lib/sqa/portfolio.rb:8`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L8)
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
### `#initial_cash=(value)`
|
|
125
|
+
|
|
126
|
+
Sets the attribute initial_cash
|
|
127
|
+
|
|
128
|
+
!!! info "Parameters"
|
|
129
|
+
|
|
130
|
+
| Name | Type | Description |
|
|
131
|
+
|------|------|-------------|
|
|
132
|
+
| `value` | `Any` | the value to set the attribute initial_cash to. |
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
??? info "Source Location"
|
|
136
|
+
[`lib/sqa/portfolio.rb:8`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L8)
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### `#commission()`
|
|
141
|
+
|
|
142
|
+
Returns the value of attribute commission.
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
??? info "Source Location"
|
|
148
|
+
[`lib/sqa/portfolio.rb:8`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L8)
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### `#commission=(value)`
|
|
153
|
+
|
|
154
|
+
Sets the attribute commission
|
|
155
|
+
|
|
156
|
+
!!! info "Parameters"
|
|
157
|
+
|
|
158
|
+
| Name | Type | Description |
|
|
159
|
+
|------|------|-------------|
|
|
160
|
+
| `value` | `Any` | the value to set the attribute commission to. |
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
??? info "Source Location"
|
|
164
|
+
[`lib/sqa/portfolio.rb:8`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L8)
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
### `#initialize(initial_cash: = 10_000.0, commission: = 0.0)`
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
!!! success "Returns"
|
|
172
|
+
|
|
173
|
+
**Type:** `Portfolio`
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
a new instance of Portfolio
|
|
178
|
+
|
|
179
|
+
??? info "Source Location"
|
|
180
|
+
[`lib/sqa/portfolio.rb:41`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L41)
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
### `#buy(ticker, shares:, price:, date: = Date.today)`
|
|
185
|
+
|
|
186
|
+
Buy shares of a stock
|
|
187
|
+
|
|
188
|
+
!!! info "Parameters"
|
|
189
|
+
|
|
190
|
+
| Name | Type | Description |
|
|
191
|
+
|------|------|-------------|
|
|
192
|
+
| `ticker` | `String` | Stock ticker symbol |
|
|
193
|
+
| `shares` | `Integer` | Number of shares to buy |
|
|
194
|
+
| `price` | `Float` | Price per share |
|
|
195
|
+
| `date` | `Date` | Date of trade |
|
|
196
|
+
!!! success "Returns"
|
|
197
|
+
|
|
198
|
+
**Type:** `Trade`
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
The executed trade
|
|
203
|
+
!!! example "Usage Examples"
|
|
204
|
+
|
|
205
|
+
```ruby
|
|
206
|
+
portfolio = SQA::Portfolio.new(initial_cash: 10_000, commission: 1.0)
|
|
207
|
+
trade = portfolio.buy('AAPL', shares: 10, price: 150.0)
|
|
208
|
+
trade.action # => :buy
|
|
209
|
+
trade.total # => 1500.0
|
|
210
|
+
portfolio.cash # => 8499.0 (10_000 - 1500 - 1.0 commission)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```ruby
|
|
214
|
+
portfolio.buy('AAPL', shares: 10, price: 150.0)
|
|
215
|
+
portfolio.buy('MSFT', shares: 5, price: 300.0)
|
|
216
|
+
portfolio.positions.size # => 2
|
|
217
|
+
```
|
|
218
|
+
??? info "Source Location"
|
|
219
|
+
[`lib/sqa/portfolio.rb:55`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L55)
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
### `#sell(ticker, shares:, price:, date: = Date.today)`
|
|
224
|
+
|
|
225
|
+
Sell shares of a stock
|
|
226
|
+
|
|
227
|
+
!!! info "Parameters"
|
|
228
|
+
|
|
229
|
+
| Name | Type | Description |
|
|
230
|
+
|------|------|-------------|
|
|
231
|
+
| `ticker` | `String` | Stock ticker symbol |
|
|
232
|
+
| `shares` | `Integer` | Number of shares to sell |
|
|
233
|
+
| `price` | `Float` | Price per share |
|
|
234
|
+
| `date` | `Date` | Date of trade |
|
|
235
|
+
!!! success "Returns"
|
|
236
|
+
|
|
237
|
+
**Type:** `Trade`
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
The executed trade
|
|
242
|
+
!!! example "Usage Examples"
|
|
243
|
+
|
|
244
|
+
```ruby
|
|
245
|
+
portfolio = SQA::Portfolio.new(initial_cash: 10_000, commission: 1.0)
|
|
246
|
+
portfolio.buy('AAPL', shares: 10, price: 150.0)
|
|
247
|
+
trade = portfolio.sell('AAPL', shares: 10, price: 160.0)
|
|
248
|
+
trade.total # => 1600.0
|
|
249
|
+
portfolio.cash # => 8498.0 + 1599.0 = 10097.0 (after commissions)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
```ruby
|
|
253
|
+
portfolio.buy('AAPL', shares: 100, price: 150.0)
|
|
254
|
+
portfolio.sell('AAPL', shares: 50, price: 160.0) # Sell half
|
|
255
|
+
portfolio.position('AAPL').shares # => 50
|
|
256
|
+
```
|
|
257
|
+
??? info "Source Location"
|
|
258
|
+
[`lib/sqa/portfolio.rb:98`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L98)
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
### `#position(ticker)`
|
|
263
|
+
|
|
264
|
+
Get current position for a ticker
|
|
265
|
+
|
|
266
|
+
!!! info "Parameters"
|
|
267
|
+
|
|
268
|
+
| Name | Type | Description |
|
|
269
|
+
|------|------|-------------|
|
|
270
|
+
| `ticker` | `String` | Stock ticker symbol |
|
|
271
|
+
!!! success "Returns"
|
|
272
|
+
|
|
273
|
+
**Type:** `Position, nil`
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
The position or nil if not found
|
|
278
|
+
|
|
279
|
+
??? info "Source Location"
|
|
280
|
+
[`lib/sqa/portfolio.rb:135`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L135)
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
### `#all_positions()`
|
|
285
|
+
|
|
286
|
+
Get all current positions
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
!!! success "Returns"
|
|
290
|
+
|
|
291
|
+
**Type:** `Hash`
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
Hash of ticker => Position
|
|
296
|
+
|
|
297
|
+
??? info "Source Location"
|
|
298
|
+
[`lib/sqa/portfolio.rb:141`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L141)
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
### `#value(current_prices = {})`
|
|
303
|
+
|
|
304
|
+
Calculate total portfolio value
|
|
305
|
+
|
|
306
|
+
!!! info "Parameters"
|
|
307
|
+
|
|
308
|
+
| Name | Type | Description |
|
|
309
|
+
|------|------|-------------|
|
|
310
|
+
| `current_prices` | `Hash` | Hash of ticker => current_price |
|
|
311
|
+
!!! success "Returns"
|
|
312
|
+
|
|
313
|
+
**Type:** `Float`
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
Total portfolio value (cash + positions)
|
|
318
|
+
!!! example "Usage Examples"
|
|
319
|
+
|
|
320
|
+
```ruby
|
|
321
|
+
portfolio = SQA::Portfolio.new(initial_cash: 10_000)
|
|
322
|
+
portfolio.buy('AAPL', shares: 10, price: 150.0)
|
|
323
|
+
portfolio.buy('MSFT', shares: 5, price: 300.0)
|
|
324
|
+
|
|
325
|
+
current_prices = { 'AAPL' => 160.0, 'MSFT' => 310.0 }
|
|
326
|
+
portfolio.value(current_prices) # => 10_000 - 1500 - 1500 + 1600 + 1550 = 10_150
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
```ruby
|
|
330
|
+
portfolio.value # Uses purchase prices if no current prices provided
|
|
331
|
+
```
|
|
332
|
+
??? info "Source Location"
|
|
333
|
+
[`lib/sqa/portfolio.rb:148`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L148)
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
### `#profit_loss(current_prices = {})`
|
|
338
|
+
|
|
339
|
+
Calculate total profit/loss across all positions
|
|
340
|
+
|
|
341
|
+
!!! info "Parameters"
|
|
342
|
+
|
|
343
|
+
| Name | Type | Description |
|
|
344
|
+
|------|------|-------------|
|
|
345
|
+
| `current_prices` | `Hash` | Hash of ticker => current_price |
|
|
346
|
+
!!! success "Returns"
|
|
347
|
+
|
|
348
|
+
**Type:** `Float`
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
Total P&L
|
|
353
|
+
|
|
354
|
+
??? info "Source Location"
|
|
355
|
+
[`lib/sqa/portfolio.rb:160`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L160)
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
### `#profit_loss_percent(current_prices = {})`
|
|
360
|
+
|
|
361
|
+
Calculate profit/loss percentage
|
|
362
|
+
|
|
363
|
+
!!! info "Parameters"
|
|
364
|
+
|
|
365
|
+
| Name | Type | Description |
|
|
366
|
+
|------|------|-------------|
|
|
367
|
+
| `current_prices` | `Hash` | Hash of ticker => current_price |
|
|
368
|
+
!!! success "Returns"
|
|
369
|
+
|
|
370
|
+
**Type:** `Float`
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
P&L percentage
|
|
375
|
+
|
|
376
|
+
??? info "Source Location"
|
|
377
|
+
[`lib/sqa/portfolio.rb:167`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L167)
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
### `#total_return(current_prices = {})`
|
|
382
|
+
|
|
383
|
+
Calculate total return (including dividends if tracked)
|
|
384
|
+
|
|
385
|
+
!!! info "Parameters"
|
|
386
|
+
|
|
387
|
+
| Name | Type | Description |
|
|
388
|
+
|------|------|-------------|
|
|
389
|
+
| `current_prices` | `Hash` | Hash of ticker => current_price |
|
|
390
|
+
!!! success "Returns"
|
|
391
|
+
|
|
392
|
+
**Type:** `Float`
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
Total return as decimal (e.g., 0.15 for 15%)
|
|
397
|
+
|
|
398
|
+
??? info "Source Location"
|
|
399
|
+
[`lib/sqa/portfolio.rb:175`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L175)
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
### `#trade_history()`
|
|
404
|
+
|
|
405
|
+
Get trade history
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
!!! success "Returns"
|
|
409
|
+
|
|
410
|
+
**Type:** `Array<Trade>`
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
Array of all trades
|
|
415
|
+
|
|
416
|
+
??? info "Source Location"
|
|
417
|
+
[`lib/sqa/portfolio.rb:182`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L182)
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
### `#summary(current_prices = {})`
|
|
422
|
+
|
|
423
|
+
Get summary statistics
|
|
424
|
+
|
|
425
|
+
!!! info "Parameters"
|
|
426
|
+
|
|
427
|
+
| Name | Type | Description |
|
|
428
|
+
|------|------|-------------|
|
|
429
|
+
| `current_prices` | `Hash` | Hash of ticker => current_price |
|
|
430
|
+
!!! success "Returns"
|
|
431
|
+
|
|
432
|
+
**Type:** `Hash`
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
Summary statistics
|
|
437
|
+
!!! example "Usage Examples"
|
|
438
|
+
|
|
439
|
+
```ruby
|
|
440
|
+
portfolio = SQA::Portfolio.new(initial_cash: 10_000, commission: 1.0)
|
|
441
|
+
portfolio.buy('AAPL', shares: 10, price: 150.0)
|
|
442
|
+
portfolio.sell('AAPL', shares: 5, price: 160.0)
|
|
443
|
+
|
|
444
|
+
summary = portfolio.summary({ 'AAPL' => 165.0 })
|
|
445
|
+
summary[:initial_cash] # => 10_000.0
|
|
446
|
+
summary[:current_cash] # => 8798.0
|
|
447
|
+
summary[:positions_count] # => 1
|
|
448
|
+
summary[:total_value] # => 9623.0
|
|
449
|
+
summary[:profit_loss_percent] # => -3.77%
|
|
450
|
+
summary[:total_trades] # => 2
|
|
451
|
+
summary[:buy_trades] # => 1
|
|
452
|
+
summary[:sell_trades] # => 1
|
|
453
|
+
```
|
|
454
|
+
??? info "Source Location"
|
|
455
|
+
[`lib/sqa/portfolio.rb:189`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L189)
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
### `#save_to_csv(filename)`
|
|
460
|
+
|
|
461
|
+
Save portfolio to CSV file
|
|
462
|
+
|
|
463
|
+
!!! info "Parameters"
|
|
464
|
+
|
|
465
|
+
| Name | Type | Description |
|
|
466
|
+
|------|------|-------------|
|
|
467
|
+
| `filename` | `String` | Path to CSV file |
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
??? info "Source Location"
|
|
471
|
+
[`lib/sqa/portfolio.rb:206`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L206)
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
### `#save_trades_to_csv(filename)`
|
|
476
|
+
|
|
477
|
+
Save trade history to CSV file
|
|
478
|
+
|
|
479
|
+
!!! info "Parameters"
|
|
480
|
+
|
|
481
|
+
| Name | Type | Description |
|
|
482
|
+
|------|------|-------------|
|
|
483
|
+
| `filename` | `String` | Path to CSV file |
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
??? info "Source Location"
|
|
487
|
+
[`lib/sqa/portfolio.rb:217`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L217)
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## 📝 Attributes
|
|
492
|
+
|
|
493
|
+
### 🔄 `positions` <small>read/write</small>
|
|
494
|
+
|
|
495
|
+
Returns the value of attribute positions.
|
|
496
|
+
|
|
497
|
+
### 🔄 `trades` <small>read/write</small>
|
|
498
|
+
|
|
499
|
+
Returns the value of attribute trades.
|
|
500
|
+
|
|
501
|
+
### 🔄 `cash` <small>read/write</small>
|
|
502
|
+
|
|
503
|
+
Returns the value of attribute cash.
|
|
504
|
+
|
|
505
|
+
### 🔄 `initial_cash` <small>read/write</small>
|
|
506
|
+
|
|
507
|
+
Returns the value of attribute initial_cash.
|
|
508
|
+
|
|
509
|
+
### 🔄 `commission` <small>read/write</small>
|
|
510
|
+
|
|
511
|
+
Returns the value of attribute commission.
|
|
512
|
+
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# 📦 SQA::Portfolio::Position
|
|
2
|
+
|
|
3
|
+
!!! note "Description"
|
|
4
|
+
Represents a single position in the portfolio
|
|
5
|
+
|
|
6
|
+
!!! abstract "Source Information"
|
|
7
|
+
**Defined in:** [`lib/sqa/portfolio.rb:11`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L11)
|
|
8
|
+
|
|
9
|
+
**Inherits from:** `Struct`
|
|
10
|
+
|
|
11
|
+
## 🔨 Instance Methods
|
|
12
|
+
|
|
13
|
+
### `#ticker=(value)`
|
|
14
|
+
|
|
15
|
+
Sets the attribute ticker
|
|
16
|
+
|
|
17
|
+
!!! info "Parameters"
|
|
18
|
+
|
|
19
|
+
| Name | Type | Description |
|
|
20
|
+
|------|------|-------------|
|
|
21
|
+
| `value` | `Object` | the value to set the attribute ticker to. |
|
|
22
|
+
!!! success "Returns"
|
|
23
|
+
|
|
24
|
+
**Type:** `Object`
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
the newly set value
|
|
29
|
+
|
|
30
|
+
??? info "Source Location"
|
|
31
|
+
[`lib/sqa/portfolio.rb:11`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L11)
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
### `#ticker()`
|
|
36
|
+
|
|
37
|
+
Returns the value of attribute ticker
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
!!! success "Returns"
|
|
41
|
+
|
|
42
|
+
**Type:** `Object`
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
the current value of ticker
|
|
47
|
+
|
|
48
|
+
??? info "Source Location"
|
|
49
|
+
[`lib/sqa/portfolio.rb:11`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L11)
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### `#shares=(value)`
|
|
54
|
+
|
|
55
|
+
Sets the attribute shares
|
|
56
|
+
|
|
57
|
+
!!! info "Parameters"
|
|
58
|
+
|
|
59
|
+
| Name | Type | Description |
|
|
60
|
+
|------|------|-------------|
|
|
61
|
+
| `value` | `Object` | the value to set the attribute shares to. |
|
|
62
|
+
!!! success "Returns"
|
|
63
|
+
|
|
64
|
+
**Type:** `Object`
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
the newly set value
|
|
69
|
+
|
|
70
|
+
??? info "Source Location"
|
|
71
|
+
[`lib/sqa/portfolio.rb:11`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L11)
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
### `#shares()`
|
|
76
|
+
|
|
77
|
+
Returns the value of attribute shares
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
!!! success "Returns"
|
|
81
|
+
|
|
82
|
+
**Type:** `Object`
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
the current value of shares
|
|
87
|
+
|
|
88
|
+
??? info "Source Location"
|
|
89
|
+
[`lib/sqa/portfolio.rb:11`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L11)
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### `#avg_cost=(value)`
|
|
94
|
+
|
|
95
|
+
Sets the attribute avg_cost
|
|
96
|
+
|
|
97
|
+
!!! info "Parameters"
|
|
98
|
+
|
|
99
|
+
| Name | Type | Description |
|
|
100
|
+
|------|------|-------------|
|
|
101
|
+
| `value` | `Object` | the value to set the attribute avg_cost to. |
|
|
102
|
+
!!! success "Returns"
|
|
103
|
+
|
|
104
|
+
**Type:** `Object`
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
the newly set value
|
|
109
|
+
|
|
110
|
+
??? info "Source Location"
|
|
111
|
+
[`lib/sqa/portfolio.rb:11`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L11)
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
### `#avg_cost()`
|
|
116
|
+
|
|
117
|
+
Returns the value of attribute avg_cost
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
!!! success "Returns"
|
|
121
|
+
|
|
122
|
+
**Type:** `Object`
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
the current value of avg_cost
|
|
127
|
+
|
|
128
|
+
??? info "Source Location"
|
|
129
|
+
[`lib/sqa/portfolio.rb:11`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L11)
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
### `#total_cost=(value)`
|
|
134
|
+
|
|
135
|
+
Sets the attribute total_cost
|
|
136
|
+
|
|
137
|
+
!!! info "Parameters"
|
|
138
|
+
|
|
139
|
+
| Name | Type | Description |
|
|
140
|
+
|------|------|-------------|
|
|
141
|
+
| `value` | `Object` | the value to set the attribute total_cost to. |
|
|
142
|
+
!!! success "Returns"
|
|
143
|
+
|
|
144
|
+
**Type:** `Object`
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
the newly set value
|
|
149
|
+
|
|
150
|
+
??? info "Source Location"
|
|
151
|
+
[`lib/sqa/portfolio.rb:11`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L11)
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
### `#total_cost()`
|
|
156
|
+
|
|
157
|
+
Returns the value of attribute total_cost
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
!!! success "Returns"
|
|
161
|
+
|
|
162
|
+
**Type:** `Object`
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
the current value of total_cost
|
|
167
|
+
|
|
168
|
+
??? info "Source Location"
|
|
169
|
+
[`lib/sqa/portfolio.rb:11`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L11)
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
### `#value(current_price)`
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
??? info "Source Location"
|
|
179
|
+
[`lib/sqa/portfolio.rb:12`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L12)
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### `#profit_loss(current_price)`
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
??? info "Source Location"
|
|
189
|
+
[`lib/sqa/portfolio.rb:16`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L16)
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
### `#profit_loss_percent(current_price)`
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
??? info "Source Location"
|
|
199
|
+
[`lib/sqa/portfolio.rb:20`](https://github.com/madbomber/sqa/blob/main/lib/sqa/portfolio.rb#L20)
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 📝 Attributes
|
|
204
|
+
|
|
205
|
+
### 🔄 `ticker` <small>read/write</small>
|
|
206
|
+
|
|
207
|
+
Returns the value of attribute ticker
|
|
208
|
+
|
|
209
|
+
### 🔄 `shares` <small>read/write</small>
|
|
210
|
+
|
|
211
|
+
Returns the value of attribute shares
|
|
212
|
+
|
|
213
|
+
### 🔄 `avg_cost` <small>read/write</small>
|
|
214
|
+
|
|
215
|
+
Returns the value of attribute avg_cost
|
|
216
|
+
|
|
217
|
+
### 🔄 `total_cost` <small>read/write</small>
|
|
218
|
+
|
|
219
|
+
Returns the value of attribute total_cost
|
|
220
|
+
|