sqa 0.0.24 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.goose/memory/development.txt +3 -0
- data/.semver +6 -0
- data/ARCHITECTURE.md +648 -0
- data/CHANGELOG.md +82 -0
- data/CLAUDE.md +653 -0
- data/COMMITS.md +196 -0
- data/DATAFRAME_ARCHITECTURE_REVIEW.md +421 -0
- data/NEXT-STEPS.md +154 -0
- data/README.md +812 -262
- data/TASKS.md +358 -0
- data/TEST_RESULTS.md +140 -0
- data/TODO.md +42 -0
- data/_notes.txt +25 -0
- data/bin/sqa-console +11 -0
- data/data/talk_talk.json +103284 -0
- data/develop_summary.md +313 -0
- data/docs/advanced/backtesting.md +206 -0
- data/docs/advanced/ensemble.md +68 -0
- data/docs/advanced/fpop.md +153 -0
- data/docs/advanced/index.md +112 -0
- data/docs/advanced/multi-timeframe.md +67 -0
- data/docs/advanced/pattern-matcher.md +75 -0
- data/docs/advanced/portfolio-optimizer.md +79 -0
- data/docs/advanced/portfolio.md +166 -0
- data/docs/advanced/risk-management.md +210 -0
- data/docs/advanced/strategy-generator.md +158 -0
- data/docs/advanced/streaming.md +209 -0
- data/docs/ai_and_ml.md +80 -0
- data/docs/api/dataframe.md +1115 -0
- data/docs/api/index.md +126 -0
- data/docs/assets/css/custom.css +88 -0
- data/docs/assets/js/mathjax.js +18 -0
- data/docs/concepts/index.md +68 -0
- data/docs/contributing/index.md +60 -0
- data/docs/data-sources/index.md +66 -0
- data/docs/data_frame.md +317 -97
- data/docs/factors_that_impact_price.md +26 -0
- data/docs/finviz.md +11 -0
- data/docs/fx_pro_bit.md +25 -0
- data/docs/genetic_programming.md +104 -0
- data/docs/getting-started/index.md +123 -0
- data/docs/getting-started/installation.md +229 -0
- data/docs/getting-started/quick-start.md +244 -0
- data/docs/i_gotta_an_idea.md +22 -0
- data/docs/index.md +163 -0
- data/docs/indicators/index.md +97 -0
- data/docs/indicators.md +110 -24
- data/docs/options.md +8 -0
- data/docs/strategies/bollinger-bands.md +146 -0
- data/docs/strategies/consensus.md +64 -0
- data/docs/strategies/custom.md +310 -0
- data/docs/strategies/ema.md +53 -0
- data/docs/strategies/index.md +92 -0
- data/docs/strategies/kbs.md +164 -0
- data/docs/strategies/macd.md +96 -0
- data/docs/strategies/market-profile.md +54 -0
- data/docs/strategies/mean-reversion.md +58 -0
- data/docs/strategies/rsi.md +95 -0
- data/docs/strategies/sma.md +55 -0
- data/docs/strategies/stochastic.md +63 -0
- data/docs/strategies/volume-breakout.md +54 -0
- data/docs/tags.md +7 -0
- data/docs/true_strength_index.md +46 -0
- data/docs/weighted_moving_average.md +48 -0
- data/examples/README.md +354 -0
- data/examples/advanced_features_example.rb +350 -0
- data/examples/fpop_analysis_example.rb +191 -0
- data/examples/genetic_programming_example.rb +148 -0
- data/examples/kbs_strategy_example.rb +208 -0
- data/examples/pattern_context_example.rb +300 -0
- data/examples/rails_app/Gemfile +34 -0
- data/examples/rails_app/README.md +416 -0
- data/examples/rails_app/app/assets/javascripts/application.js +107 -0
- data/examples/rails_app/app/assets/stylesheets/application.css +659 -0
- data/examples/rails_app/app/controllers/analysis_controller.rb +11 -0
- data/examples/rails_app/app/controllers/api/v1/stocks_controller.rb +227 -0
- data/examples/rails_app/app/controllers/application_controller.rb +22 -0
- data/examples/rails_app/app/controllers/backtest_controller.rb +11 -0
- data/examples/rails_app/app/controllers/dashboard_controller.rb +21 -0
- data/examples/rails_app/app/controllers/portfolio_controller.rb +7 -0
- data/examples/rails_app/app/views/analysis/show.html.erb +209 -0
- data/examples/rails_app/app/views/backtest/show.html.erb +171 -0
- data/examples/rails_app/app/views/dashboard/index.html.erb +118 -0
- data/examples/rails_app/app/views/dashboard/show.html.erb +408 -0
- data/examples/rails_app/app/views/errors/show.html.erb +17 -0
- data/examples/rails_app/app/views/layouts/application.html.erb +60 -0
- data/examples/rails_app/app/views/portfolio/index.html.erb +33 -0
- data/examples/rails_app/bin/rails +6 -0
- data/examples/rails_app/config/application.rb +45 -0
- data/examples/rails_app/config/boot.rb +5 -0
- data/examples/rails_app/config/database.yml +18 -0
- data/examples/rails_app/config/environment.rb +11 -0
- data/examples/rails_app/config/routes.rb +26 -0
- data/examples/rails_app/config.ru +8 -0
- data/examples/realtime_stream_example.rb +274 -0
- data/examples/sinatra_app/Gemfile +22 -0
- data/examples/sinatra_app/QUICKSTART.md +159 -0
- data/examples/sinatra_app/README.md +461 -0
- data/examples/sinatra_app/app.rb +344 -0
- data/examples/sinatra_app/config.ru +5 -0
- data/examples/sinatra_app/public/css/style.css +659 -0
- data/examples/sinatra_app/public/js/app.js +107 -0
- data/examples/sinatra_app/views/analyze.erb +306 -0
- data/examples/sinatra_app/views/backtest.erb +325 -0
- data/examples/sinatra_app/views/dashboard.erb +419 -0
- data/examples/sinatra_app/views/error.erb +58 -0
- data/examples/sinatra_app/views/index.erb +118 -0
- data/examples/sinatra_app/views/layout.erb +61 -0
- data/examples/sinatra_app/views/portfolio.erb +43 -0
- data/examples/strategy_generator_example.rb +346 -0
- data/hsa_portfolio.csv +11 -0
- data/justfile +0 -0
- data/lib/api/alpha_vantage_api.rb +462 -0
- data/lib/sqa/backtest.rb +329 -0
- data/lib/sqa/data_frame/alpha_vantage.rb +43 -65
- data/lib/sqa/data_frame/data.rb +92 -0
- data/lib/sqa/data_frame/yahoo_finance.rb +35 -43
- data/lib/sqa/data_frame.rb +148 -243
- data/lib/sqa/ensemble.rb +359 -0
- data/lib/sqa/fpop.rb +199 -0
- data/lib/sqa/gp.rb +259 -0
- data/lib/sqa/indicator.rb +5 -8
- data/lib/sqa/init.rb +15 -8
- data/lib/sqa/market_regime.rb +240 -0
- data/lib/sqa/multi_timeframe.rb +379 -0
- data/lib/sqa/pattern_matcher.rb +497 -0
- data/lib/sqa/portfolio.rb +260 -6
- data/lib/sqa/portfolio_optimizer.rb +377 -0
- data/lib/sqa/risk_manager.rb +442 -0
- data/lib/sqa/seasonal_analyzer.rb +209 -0
- data/lib/sqa/sector_analyzer.rb +300 -0
- data/lib/sqa/stock.rb +67 -125
- data/lib/sqa/strategy/bollinger_bands.rb +42 -0
- data/lib/sqa/strategy/consensus.rb +5 -2
- data/lib/sqa/strategy/kbs_strategy.rb +470 -0
- data/lib/sqa/strategy/macd.rb +46 -0
- data/lib/sqa/strategy/mp.rb +1 -1
- data/lib/sqa/strategy/stochastic.rb +60 -0
- data/lib/sqa/strategy/volume_breakout.rb +57 -0
- data/lib/sqa/strategy.rb +5 -0
- data/lib/sqa/strategy_generator.rb +947 -0
- data/lib/sqa/stream.rb +361 -0
- data/lib/sqa/version.rb +1 -7
- data/lib/sqa.rb +23 -16
- data/main.just +81 -0
- data/mkdocs.yml +288 -0
- data/trace.log +0 -0
- metadata +261 -51
- data/bin/sqa +0 -6
- data/lib/patches/dry-cli.rb +0 -228
- data/lib/sqa/activity.rb +0 -10
- data/lib/sqa/cli.rb +0 -62
- data/lib/sqa/commands/analysis.rb +0 -309
- data/lib/sqa/commands/base.rb +0 -139
- data/lib/sqa/commands/web.rb +0 -199
- data/lib/sqa/commands.rb +0 -22
- data/lib/sqa/constants.rb +0 -23
- data/lib/sqa/indicator/average_true_range.rb +0 -33
- data/lib/sqa/indicator/bollinger_bands.rb +0 -28
- data/lib/sqa/indicator/candlestick_pattern_recognizer.rb +0 -60
- data/lib/sqa/indicator/donchian_channel.rb +0 -29
- data/lib/sqa/indicator/double_top_bottom_pattern.rb +0 -34
- data/lib/sqa/indicator/elliott_wave_theory.rb +0 -57
- data/lib/sqa/indicator/exponential_moving_average.rb +0 -25
- data/lib/sqa/indicator/exponential_moving_average_trend.rb +0 -36
- data/lib/sqa/indicator/fibonacci_retracement.rb +0 -23
- data/lib/sqa/indicator/head_and_shoulders_pattern.rb +0 -26
- data/lib/sqa/indicator/market_profile.rb +0 -32
- data/lib/sqa/indicator/mean_reversion.rb +0 -37
- data/lib/sqa/indicator/momentum.rb +0 -28
- data/lib/sqa/indicator/moving_average_convergence_divergence.rb +0 -29
- data/lib/sqa/indicator/peaks_and_valleys.rb +0 -29
- data/lib/sqa/indicator/predict_next_value.rb +0 -202
- data/lib/sqa/indicator/relative_strength_index.rb +0 -47
- data/lib/sqa/indicator/simple_moving_average.rb +0 -24
- data/lib/sqa/indicator/simple_moving_average_trend.rb +0 -32
- data/lib/sqa/indicator/stochastic_oscillator.rb +0 -68
- data/lib/sqa/indicator/true_range.rb +0 -39
- data/lib/sqa/trade.rb +0 -26
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# Creating Custom Strategies
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Learn how to create your own trading strategies in the SQA framework.
|
|
6
|
+
|
|
7
|
+
## Strategy Interface
|
|
8
|
+
|
|
9
|
+
All strategies must implement a `self.trade(vector)` class method that returns `:buy`, `:sell`, or `:hold`.
|
|
10
|
+
|
|
11
|
+
## Basic Template
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
# lib/sqa/strategy/my_strategy.rb
|
|
15
|
+
|
|
16
|
+
class SQA::Strategy::MyStrategy
|
|
17
|
+
def self.trade(vector)
|
|
18
|
+
# 1. Validate input
|
|
19
|
+
return :hold unless vector.respond_to?(:prices)
|
|
20
|
+
return :hold if vector.prices.nil? || vector.prices.size < 20
|
|
21
|
+
|
|
22
|
+
# 2. Extract data
|
|
23
|
+
prices = vector.prices
|
|
24
|
+
|
|
25
|
+
# 3. Calculate indicators
|
|
26
|
+
sma = SQAI.sma(prices, period: 20)
|
|
27
|
+
rsi = SQAI.rsi(prices, period: 14)
|
|
28
|
+
|
|
29
|
+
# 4. Implement trading logic
|
|
30
|
+
if rsi.last < 30 && prices.last > sma.last
|
|
31
|
+
:buy
|
|
32
|
+
elsif rsi.last > 70 && prices.last < sma.last
|
|
33
|
+
:sell
|
|
34
|
+
else
|
|
35
|
+
:hold
|
|
36
|
+
end
|
|
37
|
+
rescue => e
|
|
38
|
+
warn "MyStrategy error: #{e.message}"
|
|
39
|
+
:hold
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Step-by-Step Guide
|
|
45
|
+
|
|
46
|
+
### 1. Create Strategy File
|
|
47
|
+
|
|
48
|
+
Create a new file in `lib/sqa/strategy/`:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
touch lib/sqa/strategy/my_strategy.rb
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2. Define Strategy Class
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
class SQA::Strategy::MyStrategy
|
|
58
|
+
# Your implementation
|
|
59
|
+
end
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3. Implement Trade Method
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
def self.trade(vector)
|
|
66
|
+
# Return :buy, :sell, or :hold
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 4. Add Error Handling
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
def self.trade(vector)
|
|
74
|
+
# Your logic
|
|
75
|
+
rescue => e
|
|
76
|
+
warn "Error: #{e.message}"
|
|
77
|
+
:hold # Safe default
|
|
78
|
+
end
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 5. Write Tests
|
|
82
|
+
|
|
83
|
+
Create `test/strategy/my_strategy_test.rb`:
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
require_relative '../test_helper'
|
|
87
|
+
require 'ostruct'
|
|
88
|
+
|
|
89
|
+
class MyStrategyTest < Minitest::Test
|
|
90
|
+
def test_buy_signal
|
|
91
|
+
prices = [100, 102, 104, 106, 108]
|
|
92
|
+
vector = OpenStruct.new(prices: prices)
|
|
93
|
+
|
|
94
|
+
signal = SQA::Strategy::MyStrategy.trade(vector)
|
|
95
|
+
assert_equal :buy, signal
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def test_hold_when_no_data
|
|
99
|
+
vector = OpenStruct.new
|
|
100
|
+
signal = SQA::Strategy::MyStrategy.trade(vector)
|
|
101
|
+
assert_equal :hold, signal
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Advanced Example
|
|
107
|
+
|
|
108
|
+
```ruby
|
|
109
|
+
class SQA::Strategy::AdvancedStrategy
|
|
110
|
+
# Constants for configuration
|
|
111
|
+
RSI_OVERSOLD = 30
|
|
112
|
+
RSI_OVERBOUGHT = 70
|
|
113
|
+
MIN_VOLUME_RATIO = 1.5
|
|
114
|
+
|
|
115
|
+
def self.trade(vector)
|
|
116
|
+
return :hold unless valid_vector?(vector)
|
|
117
|
+
|
|
118
|
+
analysis = analyze_market(vector)
|
|
119
|
+
generate_signal(analysis)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
|
|
124
|
+
def self.valid_vector?(vector)
|
|
125
|
+
vector.respond_to?(:prices) &&
|
|
126
|
+
vector.respond_to?(:volumes) &&
|
|
127
|
+
vector.prices&.size >= 50
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def self.analyze_market(vector)
|
|
131
|
+
{
|
|
132
|
+
rsi: SQAI.rsi(vector.prices, period: 14).last,
|
|
133
|
+
trend: detect_trend(vector.prices),
|
|
134
|
+
volume_spike: volume_spike?(vector.volumes)
|
|
135
|
+
}
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def self.detect_trend(prices)
|
|
139
|
+
sma_short = SQAI.sma(prices, period: 20).last
|
|
140
|
+
sma_long = SQAI.sma(prices, period: 50).last
|
|
141
|
+
|
|
142
|
+
sma_short > sma_long ? :up : :down
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def self.volume_spike?(volumes)
|
|
146
|
+
current = volumes.last
|
|
147
|
+
average = volumes.last(20).sum / 20.0
|
|
148
|
+
current > (average * MIN_VOLUME_RATIO)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def self.generate_signal(analysis)
|
|
152
|
+
if analysis[:rsi] < RSI_OVERSOLD &&
|
|
153
|
+
analysis[:trend] == :up &&
|
|
154
|
+
analysis[:volume_spike]
|
|
155
|
+
:buy
|
|
156
|
+
elsif analysis[:rsi] > RSI_OVERBOUGHT &&
|
|
157
|
+
analysis[:trend] == :down &&
|
|
158
|
+
analysis[:volume_spike]
|
|
159
|
+
:sell
|
|
160
|
+
else
|
|
161
|
+
:hold
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Best Practices
|
|
168
|
+
|
|
169
|
+
### 1. Validate Input
|
|
170
|
+
|
|
171
|
+
```ruby
|
|
172
|
+
return :hold unless vector.respond_to?(:prices)
|
|
173
|
+
return :hold if vector.prices.nil?
|
|
174
|
+
return :hold if vector.prices.size < minimum_required
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 2. Use Available Indicators
|
|
178
|
+
|
|
179
|
+
```ruby
|
|
180
|
+
# All TA-Lib indicators available via SQAI
|
|
181
|
+
rsi = SQAI.rsi(prices, period: 14)
|
|
182
|
+
macd = SQAI.macd(prices)
|
|
183
|
+
bbands = SQAI.bbands(prices, period: 20)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 3. Handle Errors Gracefully
|
|
187
|
+
|
|
188
|
+
```ruby
|
|
189
|
+
rescue => e
|
|
190
|
+
warn "#{self.name} error: #{e.message}"
|
|
191
|
+
:hold
|
|
192
|
+
end
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### 4. Test Edge Cases
|
|
196
|
+
|
|
197
|
+
- Empty data
|
|
198
|
+
- Insufficient data
|
|
199
|
+
- Nil values
|
|
200
|
+
- Extreme values
|
|
201
|
+
|
|
202
|
+
### 5. Document Your Logic
|
|
203
|
+
|
|
204
|
+
```ruby
|
|
205
|
+
# Buy when:
|
|
206
|
+
# 1. RSI indicates oversold (< 30)
|
|
207
|
+
# 2. Price above 20-day SMA (uptrend)
|
|
208
|
+
# 3. Volume confirms (> 1.5x average)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Using Your Strategy
|
|
212
|
+
|
|
213
|
+
### With Backtest
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
backtest = SQA::Backtest.new(
|
|
217
|
+
stock: stock,
|
|
218
|
+
strategy: SQA::Strategy::MyStrategy,
|
|
219
|
+
initial_cash: 10_000
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
results = backtest.run
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### With Real-Time Stream
|
|
226
|
+
|
|
227
|
+
```ruby
|
|
228
|
+
stream = SQA::Stream.new(
|
|
229
|
+
ticker: 'AAPL',
|
|
230
|
+
strategies: [SQA::Strategy::MyStrategy]
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
stream.on_signal do |signal, data|
|
|
234
|
+
puts "MyStrategy says: #{signal}"
|
|
235
|
+
end
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### With Strategy Generator
|
|
239
|
+
|
|
240
|
+
```ruby
|
|
241
|
+
# Discover patterns and auto-generate strategies
|
|
242
|
+
generator = SQA::StrategyGenerator.new(stock: stock)
|
|
243
|
+
patterns = generator.discover_patterns
|
|
244
|
+
strategy_code = generator.generate_strategy(pattern_index: 0)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Common Patterns
|
|
248
|
+
|
|
249
|
+
### Trend Following
|
|
250
|
+
|
|
251
|
+
```ruby
|
|
252
|
+
if short_ma > long_ma
|
|
253
|
+
:buy
|
|
254
|
+
elsif short_ma < long_ma
|
|
255
|
+
:sell
|
|
256
|
+
else
|
|
257
|
+
:hold
|
|
258
|
+
end
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Mean Reversion
|
|
262
|
+
|
|
263
|
+
```ruby
|
|
264
|
+
deviation = (price - average) / average
|
|
265
|
+
if deviation < -threshold
|
|
266
|
+
:buy
|
|
267
|
+
elsif deviation > threshold
|
|
268
|
+
:sell
|
|
269
|
+
else
|
|
270
|
+
:hold
|
|
271
|
+
end
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Momentum
|
|
275
|
+
|
|
276
|
+
```ruby
|
|
277
|
+
if rsi < oversold_level
|
|
278
|
+
:buy
|
|
279
|
+
elsif rsi > overbought_level
|
|
280
|
+
:sell
|
|
281
|
+
else
|
|
282
|
+
:hold
|
|
283
|
+
end
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Breakout
|
|
287
|
+
|
|
288
|
+
```ruby
|
|
289
|
+
if price > recent_high && volume > threshold
|
|
290
|
+
:buy
|
|
291
|
+
elsif price < recent_low && volume > threshold
|
|
292
|
+
:sell
|
|
293
|
+
else
|
|
294
|
+
:hold
|
|
295
|
+
end
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Next Steps
|
|
299
|
+
|
|
300
|
+
1. Study existing strategies in `lib/sqa/strategy/`
|
|
301
|
+
2. Read [Backtesting Guide](../advanced/backtesting.md)
|
|
302
|
+
3. Explore [Strategy Generator](../advanced/strategy-generator.md)
|
|
303
|
+
4. Learn about [Risk Management](../advanced/risk-management.md)
|
|
304
|
+
|
|
305
|
+
## Related
|
|
306
|
+
|
|
307
|
+
- [KBS Strategy](kbs.md) - Rule-based strategies
|
|
308
|
+
- [Consensus](consensus.md) - Combining strategies
|
|
309
|
+
- [Backtesting](../advanced/backtesting.md) - Testing strategies
|
|
310
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# EMA (Exponential Moving Average) Strategy
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Similar to SMA but gives more weight to recent prices, making it more responsive to price changes.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
Uses EMA crossovers for signals:
|
|
10
|
+
- **Short EMA**: 12 or 20-period
|
|
11
|
+
- **Long EMA**: 26 or 50-period
|
|
12
|
+
|
|
13
|
+
## Trading Signals
|
|
14
|
+
|
|
15
|
+
### Buy Signal
|
|
16
|
+
Short EMA crosses above long EMA.
|
|
17
|
+
|
|
18
|
+
### Sell Signal
|
|
19
|
+
Short EMA crosses below long EMA.
|
|
20
|
+
|
|
21
|
+
## Usage Example
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
prices = stock.df["adj_close_price"].to_a
|
|
25
|
+
|
|
26
|
+
ema_short = SQAI.ema(prices, period: 12)
|
|
27
|
+
ema_long = SQAI.ema(prices, period: 26)
|
|
28
|
+
|
|
29
|
+
vector = OpenStruct.new(
|
|
30
|
+
ema_short: ema_short,
|
|
31
|
+
ema_long: ema_long
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
signal = SQA::Strategy::EMA.trade(vector)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Characteristics
|
|
38
|
+
|
|
39
|
+
- **Complexity**: Low
|
|
40
|
+
- **Best Market**: Trending
|
|
41
|
+
- **Win Rate**: 45-55%
|
|
42
|
+
|
|
43
|
+
## Strengths
|
|
44
|
+
|
|
45
|
+
✅ Faster than SMA
|
|
46
|
+
✅ Better for short-term trading
|
|
47
|
+
✅ Reduces lag
|
|
48
|
+
|
|
49
|
+
## Weaknesses
|
|
50
|
+
|
|
51
|
+
❌ More false signals
|
|
52
|
+
❌ Still lags in fast markets
|
|
53
|
+
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Trading Strategies
|
|
2
|
+
|
|
3
|
+
Explore SQA's comprehensive suite of trading strategies.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
SQA provides 13+ built-in trading strategies, from simple moving average crossovers to advanced rule-based systems. All strategies follow a common interface and can be easily backtested or combined.
|
|
8
|
+
|
|
9
|
+
## Strategy Categories
|
|
10
|
+
|
|
11
|
+
### Trend-Following Strategies
|
|
12
|
+
Strategies that identify and follow market trends:
|
|
13
|
+
|
|
14
|
+
- **SMA Strategy** - Simple Moving Average crossovers
|
|
15
|
+
- **EMA Strategy** - Exponential Moving Average crossovers
|
|
16
|
+
- **MACD Strategy** - Moving Average Convergence Divergence
|
|
17
|
+
|
|
18
|
+
### Momentum Strategies
|
|
19
|
+
Strategies based on price momentum and oscillators:
|
|
20
|
+
|
|
21
|
+
- **RSI Strategy** - Relative Strength Index (oversold/overbought)
|
|
22
|
+
- **Stochastic Strategy** - Stochastic oscillator crossovers
|
|
23
|
+
|
|
24
|
+
### Volatility Strategies
|
|
25
|
+
Strategies that use volatility measures:
|
|
26
|
+
|
|
27
|
+
- **Bollinger Bands Strategy** - Price touches bands
|
|
28
|
+
- **ATR-based Strategies** - Average True Range volatility
|
|
29
|
+
|
|
30
|
+
### Volume Strategies
|
|
31
|
+
Strategies incorporating volume analysis:
|
|
32
|
+
|
|
33
|
+
- **Volume Breakout** - High volume price breakouts
|
|
34
|
+
|
|
35
|
+
### Mean Reversion
|
|
36
|
+
Strategies assuming prices return to average:
|
|
37
|
+
|
|
38
|
+
- **Mean Reversion Strategy** - Statistical mean reversion
|
|
39
|
+
|
|
40
|
+
### Advanced Strategies
|
|
41
|
+
Complex, rule-based approaches:
|
|
42
|
+
|
|
43
|
+
- **KBS Strategy** - Knowledge-Based System with RETE engine
|
|
44
|
+
- **Consensus Strategy** - Aggregates multiple strategies
|
|
45
|
+
|
|
46
|
+
## Using Strategies
|
|
47
|
+
|
|
48
|
+
### Basic Usage
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
require 'sqa'
|
|
52
|
+
require 'ostruct'
|
|
53
|
+
|
|
54
|
+
# Create data vector
|
|
55
|
+
vector = OpenStruct.new(
|
|
56
|
+
rsi: { trend: :over_sold },
|
|
57
|
+
prices: [100, 102, 105, 103, 107]
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Execute strategy
|
|
61
|
+
signal = SQA::Strategy::RSI.trade(vector)
|
|
62
|
+
# => :buy, :sell, or :hold
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Backtesting
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
backtest = SQA::Backtest.new(
|
|
69
|
+
stock: stock,
|
|
70
|
+
strategy: SQA::Strategy::MACD,
|
|
71
|
+
initial_cash: 10_000
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
results = backtest.run
|
|
75
|
+
puts "Return: #{results.total_return}%"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Strategy Comparison
|
|
79
|
+
|
|
80
|
+
| Strategy | Complexity | Best For | Typical Win Rate |
|
|
81
|
+
|----------|------------|----------|------------------|
|
|
82
|
+
| SMA | Low | Trending markets | 45-55% |
|
|
83
|
+
| RSI | Low | Range-bound markets | 50-60% |
|
|
84
|
+
| MACD | Medium | Trending markets | 45-55% |
|
|
85
|
+
| Bollinger Bands | Medium | Volatile markets | 50-60% |
|
|
86
|
+
| KBS | High | Complex rules | Varies |
|
|
87
|
+
|
|
88
|
+
## Next Steps
|
|
89
|
+
|
|
90
|
+
- [Built-in Strategies](bollinger-bands.md) - Explore each strategy in detail
|
|
91
|
+
- [Custom Strategies](custom.md) - Create your own strategies
|
|
92
|
+
- [Backtesting](../advanced/backtesting.md) - Test strategies historically
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# KBS (Knowledge-Based Strategy)
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Advanced rule-based trading system using RETE forward-chaining inference engine. Combines multiple indicators with custom logic rules.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
Defines trading rules with conditions and actions:
|
|
10
|
+
- **Conditions** (`on`): Facts that must be true
|
|
11
|
+
- **Actions** (`perform`): What to do when conditions met
|
|
12
|
+
|
|
13
|
+
## Rule Definition
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
strategy = SQA::Strategy::KBS.new(load_defaults: true)
|
|
17
|
+
kb = strategy.kb
|
|
18
|
+
|
|
19
|
+
# Add custom rule
|
|
20
|
+
strategy.add_rule :buy_oversold_uptrend do
|
|
21
|
+
on :rsi, { level: :oversold }
|
|
22
|
+
on :trend, { short_term: :up }
|
|
23
|
+
perform do
|
|
24
|
+
kb.assert(:signal, { action: :buy, confidence: :high })
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Default Rules
|
|
30
|
+
|
|
31
|
+
The KBS strategy includes 10 default rules:
|
|
32
|
+
1. Buy on RSI oversold in uptrend
|
|
33
|
+
2. Sell on RSI overbought in downtrend
|
|
34
|
+
3. Buy on bullish MACD crossover
|
|
35
|
+
4. Sell on bearish MACD crossover
|
|
36
|
+
5. Buy at lower Bollinger Band
|
|
37
|
+
6. Sell at upper Bollinger Band
|
|
38
|
+
7. Buy on stochastic oversold crossover
|
|
39
|
+
8. Sell on stochastic overbought crossover
|
|
40
|
+
9. Buy on SMA golden cross
|
|
41
|
+
10. Sell on SMA death cross
|
|
42
|
+
|
|
43
|
+
## Usage Example
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
# Use with default rules
|
|
47
|
+
strategy = SQA::Strategy::KBS.new(load_defaults: true)
|
|
48
|
+
|
|
49
|
+
# Provide market data
|
|
50
|
+
prices = stock.df["adj_close_price"].to_a
|
|
51
|
+
vector = OpenStruct.new(
|
|
52
|
+
rsi: SQAI.rsi(prices, period: 14),
|
|
53
|
+
prices: prices
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
signal = strategy.execute(vector)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Advanced Example
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
# Create custom strategy without defaults
|
|
63
|
+
strategy = SQA::Strategy::KBS.new(load_defaults: false)
|
|
64
|
+
kb = strategy.kb
|
|
65
|
+
|
|
66
|
+
# Define sophisticated multi-condition rule
|
|
67
|
+
strategy.add_rule :strong_buy do
|
|
68
|
+
on :rsi, { level: :oversold }
|
|
69
|
+
on :macd, { crossover: :bullish }
|
|
70
|
+
on :volume, { level: :high }
|
|
71
|
+
without :position # Don't buy if already holding
|
|
72
|
+
|
|
73
|
+
perform do
|
|
74
|
+
kb.assert(:signal, {
|
|
75
|
+
action: :buy,
|
|
76
|
+
confidence: :high,
|
|
77
|
+
reason: :triple_confirmation
|
|
78
|
+
})
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Execute
|
|
83
|
+
signal = strategy.execute(vector)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Confidence Levels
|
|
87
|
+
|
|
88
|
+
Signals include confidence scoring:
|
|
89
|
+
- **High**: 1.0
|
|
90
|
+
- **Medium**: 0.6
|
|
91
|
+
- **Low**: 0.3
|
|
92
|
+
|
|
93
|
+
Multiple rules can fire, with aggregate confidence determining final signal.
|
|
94
|
+
|
|
95
|
+
## Characteristics
|
|
96
|
+
|
|
97
|
+
- **Complexity**: High
|
|
98
|
+
- **Best Market**: All markets (depends on rules)
|
|
99
|
+
- **Win Rate**: Varies (50-70% with good rules)
|
|
100
|
+
|
|
101
|
+
## Strengths
|
|
102
|
+
|
|
103
|
+
✅ Highly customizable
|
|
104
|
+
✅ Combines multiple indicators
|
|
105
|
+
✅ Confidence scoring
|
|
106
|
+
✅ Forward-chaining inference
|
|
107
|
+
✅ Can encode expert knowledge
|
|
108
|
+
|
|
109
|
+
## Weaknesses
|
|
110
|
+
|
|
111
|
+
❌ Complex to configure
|
|
112
|
+
❌ Requires domain knowledge
|
|
113
|
+
❌ Can be slow with many rules
|
|
114
|
+
❌ Overfitting risk
|
|
115
|
+
|
|
116
|
+
## Tips
|
|
117
|
+
|
|
118
|
+
1. **Start Simple**: Begin with 2-3 rules
|
|
119
|
+
2. **Test Thoroughly**: Backtest each rule independently
|
|
120
|
+
3. **Avoid Conflicts**: Ensure rules don't contradict
|
|
121
|
+
4. **Use Confidence**: Combine weak signals for stronger conviction
|
|
122
|
+
5. **Monitor Performance**: Track which rules fire most often
|
|
123
|
+
|
|
124
|
+
## Available Facts
|
|
125
|
+
|
|
126
|
+
The KBS strategy processes these fact types:
|
|
127
|
+
- `:rsi` - RSI indicator data
|
|
128
|
+
- `:macd` - MACD crossovers
|
|
129
|
+
- `:trend` - Price trend analysis
|
|
130
|
+
- `:bollinger` - Bollinger Band position
|
|
131
|
+
- `:stochastic` - Stochastic oscillator
|
|
132
|
+
- `:volume` - Volume analysis
|
|
133
|
+
- `:sma_crossover` - SMA crossovers
|
|
134
|
+
|
|
135
|
+
## DSL Keywords
|
|
136
|
+
|
|
137
|
+
- `on` - Assert condition (fact must exist with attributes)
|
|
138
|
+
- `without` - Negated condition (fact must NOT exist)
|
|
139
|
+
- `perform` - Action to execute when rule fires
|
|
140
|
+
|
|
141
|
+
## Important Note
|
|
142
|
+
|
|
143
|
+
Due to KBS gem DSL limitations, you must use `kb.assert` (not just `assert`) inside `perform` blocks:
|
|
144
|
+
|
|
145
|
+
```ruby
|
|
146
|
+
# CORRECT
|
|
147
|
+
kb = strategy.kb
|
|
148
|
+
strategy.add_rule :my_rule do
|
|
149
|
+
on :condition
|
|
150
|
+
perform { kb.assert(:signal, { action: :buy }) }
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# INCORRECT
|
|
154
|
+
strategy.add_rule :my_rule do
|
|
155
|
+
on :condition
|
|
156
|
+
perform { assert(:signal, { action: :buy }) } # Won't work!
|
|
157
|
+
end
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Related
|
|
161
|
+
|
|
162
|
+
- [Strategy Generator](../advanced/strategy-generator.md) - Auto-generate rules
|
|
163
|
+
- [Genetic Programming](../genetic_programming.md) - Optimize rule parameters
|
|
164
|
+
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# MACD Strategy
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Moving Average Convergence Divergence (MACD) is a trend-following momentum indicator that shows the relationship between two moving averages.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
MACD consists of three components:
|
|
10
|
+
- **MACD Line**: 12-period EMA - 26-period EMA
|
|
11
|
+
- **Signal Line**: 9-period EMA of MACD Line
|
|
12
|
+
- **Histogram**: MACD Line - Signal Line
|
|
13
|
+
|
|
14
|
+
## Trading Signals
|
|
15
|
+
|
|
16
|
+
### Buy Signal (Bullish Crossover)
|
|
17
|
+
MACD line crosses **above** the signal line.
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
SQA::Strategy::MACD.trade(vector) # => :buy
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Sell Signal (Bearish Crossover)
|
|
24
|
+
MACD line crosses **below** the signal line.
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
SQA::Strategy::MACD.trade(vector) # => :sell
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage Example
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
stock = SQA::Stock.new(ticker: 'AAPL')
|
|
34
|
+
prices = stock.df["adj_close_price"].to_a
|
|
35
|
+
|
|
36
|
+
# Calculate MACD
|
|
37
|
+
macd_line, signal_line, histogram = SQAI.macd(
|
|
38
|
+
prices,
|
|
39
|
+
fast_period: 12,
|
|
40
|
+
slow_period: 26,
|
|
41
|
+
signal_period: 9
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
vector = OpenStruct.new(
|
|
45
|
+
macd: [macd_line, signal_line, histogram]
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
signal = SQA::Strategy::MACD.trade(vector)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Parameters
|
|
52
|
+
|
|
53
|
+
| Parameter | Default | Description |
|
|
54
|
+
|-----------|---------|-------------|
|
|
55
|
+
| Fast Period | 12 | Fast EMA period |
|
|
56
|
+
| Slow Period | 26 | Slow EMA period |
|
|
57
|
+
| Signal Period | 9 | Signal line EMA period |
|
|
58
|
+
|
|
59
|
+
## Characteristics
|
|
60
|
+
|
|
61
|
+
| Attribute | Value |
|
|
62
|
+
|-----------|-------|
|
|
63
|
+
| Complexity | Medium |
|
|
64
|
+
| Best Market | Trending |
|
|
65
|
+
| Win Rate | 45-55% |
|
|
66
|
+
| Time Horizon | Medium to long term |
|
|
67
|
+
|
|
68
|
+
## Strengths
|
|
69
|
+
|
|
70
|
+
- ✅ Excellent trend following
|
|
71
|
+
- ✅ Combines trend and momentum
|
|
72
|
+
- ✅ Clear crossover signals
|
|
73
|
+
- ✅ Can detect trend changes early
|
|
74
|
+
|
|
75
|
+
## Weaknesses
|
|
76
|
+
|
|
77
|
+
- ❌ Lags in fast markets
|
|
78
|
+
- ❌ Whipsaws in ranging markets
|
|
79
|
+
- ❌ False signals during consolidation
|
|
80
|
+
|
|
81
|
+
## Tips
|
|
82
|
+
|
|
83
|
+
1. **Confirm with Trend**: Best in established trends
|
|
84
|
+
2. **Histogram Divergence**: Watch for divergence with price
|
|
85
|
+
3. **Zero Line Cross**: Additional confirmation signal
|
|
86
|
+
4. **Multiple Timeframes**: Align daily and weekly signals
|
|
87
|
+
|
|
88
|
+
## Related Strategies
|
|
89
|
+
|
|
90
|
+
- [EMA](ema.md) - Uses moving average crossovers
|
|
91
|
+
- [SMA](sma.md) - Similar crossover approach
|
|
92
|
+
- [RSI](rsi.md) - Complementary momentum indicator
|
|
93
|
+
|
|
94
|
+
## Further Reading
|
|
95
|
+
|
|
96
|
+
- [MACD on Investopedia](https://www.investopedia.com/terms/m/macd.asp)
|