sqa 0.0.24 → 0.0.32
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 +95 -0
- data/CLAUDE.md +674 -0
- data/COMMITS.md +196 -0
- data/DATAFRAME_ARCHITECTURE_REVIEW.md +421 -0
- data/NEXT-STEPS.md +154 -0
- data/README.md +839 -265
- 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 +1114 -0
- data/docs/api/index.md +126 -0
- data/docs/assets/css/custom.css +88 -0
- data/docs/assets/images/sqa.jpg +0 -0
- data/docs/assets/js/mathjax.js +18 -0
- data/docs/concepts/index.md +60 -0
- data/docs/contributing/index.md +60 -0
- data/docs/data-sources/index.md +66 -0
- data/docs/data_frame.md +316 -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 +107 -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 +161 -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/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 +42 -0
- data/examples/sinatra_app/Gemfile.lock +268 -0
- data/examples/sinatra_app/QUICKSTART.md +169 -0
- data/examples/sinatra_app/README.md +471 -0
- data/examples/sinatra_app/RUNNING_WITHOUT_TALIB.md +90 -0
- data/examples/sinatra_app/TROUBLESHOOTING.md +95 -0
- data/examples/sinatra_app/app.rb +404 -0
- data/examples/sinatra_app/config.ru +5 -0
- data/examples/sinatra_app/public/css/style.css +723 -0
- data/examples/sinatra_app/public/debug_macd.html +82 -0
- data/examples/sinatra_app/public/js/app.js +107 -0
- data/examples/sinatra_app/start.sh +53 -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 +831 -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 +51 -63
- 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 +154 -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 +16 -6
- 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 +131 -127
- 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/ticker.rb +9 -2
- data/lib/sqa/version.rb +1 -7
- data/lib/sqa.rb +35 -20
- data/main.just +81 -0
- data/mkdocs.yml +252 -0
- data/trace.log +0 -0
- metadata +265 -69
- data/bin/sqa +0 -6
- data/docs/alpha_vantage_technical_indicators.md +0 -62
- data/docs/average_true_range.md +0 -9
- data/docs/bollinger_bands.md +0 -15
- data/docs/candlestick_pattern_recognizer.md +0 -4
- data/docs/donchian_channel.md +0 -5
- data/docs/double_top_bottom_pattern.md +0 -3
- data/docs/exponential_moving_average.md +0 -19
- data/docs/fibonacci_retracement.md +0 -30
- data/docs/head_and_shoulders_pattern.md +0 -3
- data/docs/market_profile.md +0 -4
- data/docs/momentum.md +0 -19
- data/docs/moving_average_convergence_divergence.md +0 -23
- data/docs/peaks_and_valleys.md +0 -11
- data/docs/relative_strength_index.md +0 -6
- data/docs/simple_moving_average.md +0 -8
- data/docs/stochastic_oscillator.md +0 -4
- data/docs/ta_lib.md +0 -160
- data/docs/true_range.md +0 -12
- 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,54 @@
|
|
|
1
|
+
# Market Profile Strategy
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Uses market profile analysis to identify support and resistance levels, generating signals when price reaches these key levels.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
Analyzes price distribution to find:
|
|
10
|
+
- **Value Area**: Where most trading occurred
|
|
11
|
+
- **Support**: Lower boundary (buy zone)
|
|
12
|
+
- **Resistance**: Upper boundary (sell zone)
|
|
13
|
+
|
|
14
|
+
## Trading Signals
|
|
15
|
+
|
|
16
|
+
### Buy Signal
|
|
17
|
+
Price at support level (`:support`).
|
|
18
|
+
|
|
19
|
+
### Sell Signal
|
|
20
|
+
Price at resistance level (`:resistance`).
|
|
21
|
+
|
|
22
|
+
### Hold Signal
|
|
23
|
+
Price within value area (`:mixed`).
|
|
24
|
+
|
|
25
|
+
## Usage Example
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
# Market profile data typically comes from
|
|
29
|
+
# price/volume distribution analysis
|
|
30
|
+
vector = OpenStruct.new(
|
|
31
|
+
market_profile: :support # or :resistance, :mixed
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
signal = SQA::Strategy::MP.trade(vector)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Characteristics
|
|
38
|
+
|
|
39
|
+
- **Complexity**: High
|
|
40
|
+
- **Best Market**: Range-bound
|
|
41
|
+
- **Win Rate**: 55-65%
|
|
42
|
+
|
|
43
|
+
## Strengths
|
|
44
|
+
|
|
45
|
+
✅ Identifies key price levels
|
|
46
|
+
✅ Works well for intraday trading
|
|
47
|
+
✅ Statistical basis
|
|
48
|
+
|
|
49
|
+
## Weaknesses
|
|
50
|
+
|
|
51
|
+
❌ Requires volume profile data
|
|
52
|
+
❌ Complex to calculate
|
|
53
|
+
❌ Less effective in trending markets
|
|
54
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Mean Reversion Strategy
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Based on the theory that prices tend to return to their average over time. Buys when price is below average and sells when above.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
Calculates distance from moving average:
|
|
10
|
+
- **Below average**: Expect price to rise (buy)
|
|
11
|
+
- **Above average**: Expect price to fall (sell)
|
|
12
|
+
|
|
13
|
+
## Trading Signals
|
|
14
|
+
|
|
15
|
+
### Buy Signal
|
|
16
|
+
Price significantly below SMA (undervalued).
|
|
17
|
+
|
|
18
|
+
### Sell Signal
|
|
19
|
+
Price significantly above SMA (overvalued).
|
|
20
|
+
|
|
21
|
+
## Usage Example
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
prices = stock.df["adj_close_price"].to_a
|
|
25
|
+
sma = SQAI.sma(prices, period: 20)
|
|
26
|
+
|
|
27
|
+
current_price = prices.last
|
|
28
|
+
current_sma = sma.last
|
|
29
|
+
deviation = ((current_price - current_sma) / current_sma) * 100
|
|
30
|
+
|
|
31
|
+
# Buy if more than 5% below SMA
|
|
32
|
+
signal = if deviation < -5.0
|
|
33
|
+
:buy
|
|
34
|
+
elsif deviation > 5.0
|
|
35
|
+
:sell
|
|
36
|
+
else
|
|
37
|
+
:hold
|
|
38
|
+
end
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Characteristics
|
|
42
|
+
|
|
43
|
+
- **Complexity**: Low
|
|
44
|
+
- **Best Market**: Range-bound, low volatility
|
|
45
|
+
- **Win Rate**: 55-65%
|
|
46
|
+
|
|
47
|
+
## Strengths
|
|
48
|
+
|
|
49
|
+
✅ High win rate in ranging markets
|
|
50
|
+
✅ Clear mathematical basis
|
|
51
|
+
✅ Works well with statistical analysis
|
|
52
|
+
|
|
53
|
+
## Weaknesses
|
|
54
|
+
|
|
55
|
+
❌ Fails in trending markets
|
|
56
|
+
❌ Can lead to "catching falling knives"
|
|
57
|
+
❌ Requires stable market conditions
|
|
58
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# RSI Strategy
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Relative Strength Index (RSI) strategy identifies overbought and oversold conditions using momentum oscillators. It generates signals when RSI crosses key thresholds.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
RSI is a momentum oscillator that ranges from 0 to 100:
|
|
10
|
+
- **Over 70**: Overbought (sell signal)
|
|
11
|
+
- **Under 30**: Oversold (buy signal)
|
|
12
|
+
- **30-70**: Neutral (hold)
|
|
13
|
+
|
|
14
|
+
## Trading Signals
|
|
15
|
+
|
|
16
|
+
### Buy Signal (`rsi.level == :oversold`)
|
|
17
|
+
```ruby
|
|
18
|
+
SQA::Strategy::RSI.trade(vector) # => :buy when RSI < 30
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Sell Signal (`rsi.level == :overbought`)
|
|
22
|
+
```ruby
|
|
23
|
+
SQA::Strategy::RSI.trade(vector) # => :sell when RSI > 70
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage Example
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
require 'sqa'
|
|
30
|
+
require 'ostruct'
|
|
31
|
+
|
|
32
|
+
stock = SQA::Stock.new(ticker: 'AAPL')
|
|
33
|
+
prices = stock.df["adj_close_price"].to_a
|
|
34
|
+
|
|
35
|
+
# Calculate RSI using TA-Lib
|
|
36
|
+
rsi_values = SQAI.rsi(prices, period: 14)
|
|
37
|
+
|
|
38
|
+
# Create indicator data structure
|
|
39
|
+
rsi_data = {
|
|
40
|
+
value: rsi_values.last,
|
|
41
|
+
trend: rsi_values.last < 30 ? :over_sold :
|
|
42
|
+
rsi_values.last > 70 ? :over_bought : :neutral
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
vector = OpenStruct.new(rsi: rsi_data)
|
|
46
|
+
signal = SQA::Strategy::RSI.trade(vector)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Parameters
|
|
50
|
+
|
|
51
|
+
| Parameter | Default | Description |
|
|
52
|
+
|-----------|---------|-------------|
|
|
53
|
+
| Period | 14 | Number of periods for RSI calculation |
|
|
54
|
+
| Oversold | 30 | Lower threshold for buy signals |
|
|
55
|
+
| Overbought | 70 | Upper threshold for sell signals |
|
|
56
|
+
|
|
57
|
+
## Characteristics
|
|
58
|
+
|
|
59
|
+
| Attribute | Value |
|
|
60
|
+
|-----------|-------|
|
|
61
|
+
| Complexity | Low |
|
|
62
|
+
| Best Market | Range-bound, volatile |
|
|
63
|
+
| Win Rate | 50-60% |
|
|
64
|
+
| Time Horizon | Short to medium term |
|
|
65
|
+
|
|
66
|
+
## Strengths
|
|
67
|
+
|
|
68
|
+
- ✅ Simple and well-understood
|
|
69
|
+
- ✅ Works in ranging markets
|
|
70
|
+
- ✅ Can identify divergences
|
|
71
|
+
- ✅ Fast response to price changes
|
|
72
|
+
|
|
73
|
+
## Weaknesses
|
|
74
|
+
|
|
75
|
+
- ❌ Fails in strong trends
|
|
76
|
+
- ❌ Can stay overbought/oversold for extended periods
|
|
77
|
+
- ❌ Generates false signals
|
|
78
|
+
|
|
79
|
+
## Tips
|
|
80
|
+
|
|
81
|
+
1. **Combine with Trend**: Only take buy signals in uptrends
|
|
82
|
+
2. **Adjust Thresholds**: Use 20/80 for more conservative signals
|
|
83
|
+
3. **Watch Divergences**: Price makes new highs but RSI doesn't (bearish divergence)
|
|
84
|
+
4. **Volume Confirmation**: Stronger signals with high volume
|
|
85
|
+
|
|
86
|
+
## Related Strategies
|
|
87
|
+
|
|
88
|
+
- [Stochastic](stochastic.md) - Similar momentum oscillator
|
|
89
|
+
- [MACD](macd.md) - Trend-following momentum
|
|
90
|
+
- [Bollinger Bands](bollinger-bands.md) - Volatility-based signals
|
|
91
|
+
|
|
92
|
+
## Further Reading
|
|
93
|
+
|
|
94
|
+
- [RSI on Investopedia](https://www.investopedia.com/terms/r/rsi.asp)
|
|
95
|
+
- [Technical Indicators](../indicators/index.md)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# SMA (Simple Moving Average) Strategy
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The SMA strategy uses crossovers of short-term and long-term simple moving averages to identify trend changes and generate trading signals.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
Compares two SMAs:
|
|
10
|
+
- **Short SMA**: Faster, more responsive (e.g., 50-day)
|
|
11
|
+
- **Long SMA**: Slower, smoother (e.g., 200-day)
|
|
12
|
+
|
|
13
|
+
## Trading Signals
|
|
14
|
+
|
|
15
|
+
### Buy Signal (Golden Cross)
|
|
16
|
+
Short SMA crosses **above** long SMA.
|
|
17
|
+
|
|
18
|
+
### Sell Signal (Death Cross)
|
|
19
|
+
Short SMA crosses **below** long SMA.
|
|
20
|
+
|
|
21
|
+
## Usage Example
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
stock = SQA::Stock.new(ticker: 'AAPL')
|
|
25
|
+
prices = stock.df["adj_close_price"].to_a
|
|
26
|
+
|
|
27
|
+
sma_short = SQAI.sma(prices, period: 50)
|
|
28
|
+
sma_long = SQAI.sma(prices, period: 200)
|
|
29
|
+
|
|
30
|
+
vector = OpenStruct.new(
|
|
31
|
+
sma_short: sma_short,
|
|
32
|
+
sma_long: sma_long
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
signal = SQA::Strategy::SMA.trade(vector)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Characteristics
|
|
39
|
+
|
|
40
|
+
- **Complexity**: Low
|
|
41
|
+
- **Best Market**: Trending
|
|
42
|
+
- **Win Rate**: 45-55%
|
|
43
|
+
|
|
44
|
+
## Strengths
|
|
45
|
+
|
|
46
|
+
✅ Simple and reliable
|
|
47
|
+
✅ Filters market noise
|
|
48
|
+
✅ Identifies major trends
|
|
49
|
+
|
|
50
|
+
## Weaknesses
|
|
51
|
+
|
|
52
|
+
❌ Significant lag
|
|
53
|
+
❌ Late entry/exit
|
|
54
|
+
❌ Poor in ranging markets
|
|
55
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Stochastic Oscillator Strategy
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Compares closing price to the price range over a period to identify overbought/oversold conditions and momentum changes.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
Calculates two lines:
|
|
10
|
+
- **%K Line**: (Current Close - Lowest Low) / (Highest High - Lowest Low) × 100
|
|
11
|
+
- **%D Line**: 3-period SMA of %K
|
|
12
|
+
|
|
13
|
+
Range: 0-100
|
|
14
|
+
|
|
15
|
+
## Trading Signals
|
|
16
|
+
|
|
17
|
+
### Buy Signal
|
|
18
|
+
- %K crosses above %D
|
|
19
|
+
- Both below 20 (oversold zone)
|
|
20
|
+
|
|
21
|
+
### Sell Signal
|
|
22
|
+
- %K crosses below %D
|
|
23
|
+
- Both above 80 (overbought zone)
|
|
24
|
+
|
|
25
|
+
## Usage Example
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
high = stock.df["high_price"].to_a
|
|
29
|
+
low = stock.df["low_price"].to_a
|
|
30
|
+
close = stock.df["adj_close_price"].to_a
|
|
31
|
+
|
|
32
|
+
stoch_k, stoch_d = SQAI.stoch(
|
|
33
|
+
high, low, close,
|
|
34
|
+
fastk_period: 14,
|
|
35
|
+
slowk_period: 3,
|
|
36
|
+
slowd_period: 3
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
vector = OpenStruct.new(
|
|
40
|
+
stoch_k: stoch_k,
|
|
41
|
+
stoch_d: stoch_d
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
signal = SQA::Strategy::Stochastic.trade(vector)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Characteristics
|
|
48
|
+
|
|
49
|
+
- **Complexity**: Medium
|
|
50
|
+
- **Best Market**: Range-bound
|
|
51
|
+
- **Win Rate**: 50-60%
|
|
52
|
+
|
|
53
|
+
## Strengths
|
|
54
|
+
|
|
55
|
+
✅ Good for reversals
|
|
56
|
+
✅ Works in ranging markets
|
|
57
|
+
✅ Early signals
|
|
58
|
+
|
|
59
|
+
## Weaknesses
|
|
60
|
+
|
|
61
|
+
❌ Many false signals in trends
|
|
62
|
+
❌ Can stay overbought/oversold
|
|
63
|
+
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Volume Breakout Strategy
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Identifies price breakouts confirmed by high trading volume for stronger signal reliability.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
Looks for:
|
|
10
|
+
1. Price breaking above recent high or below recent low
|
|
11
|
+
2. Volume exceeding 1.5x the average volume
|
|
12
|
+
|
|
13
|
+
## Trading Signals
|
|
14
|
+
|
|
15
|
+
### Buy Signal
|
|
16
|
+
- Price breaks above 20-period high
|
|
17
|
+
- Volume > 1.5× average volume
|
|
18
|
+
|
|
19
|
+
### Sell Signal
|
|
20
|
+
- Price breaks below 20-period low
|
|
21
|
+
- Volume > 1.5× average volume
|
|
22
|
+
|
|
23
|
+
## Usage Example
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
prices = stock.df["adj_close_price"].to_a
|
|
27
|
+
volumes = stock.df["volume"].to_a
|
|
28
|
+
|
|
29
|
+
vector = OpenStruct.new(
|
|
30
|
+
prices: prices,
|
|
31
|
+
volumes: volumes
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
signal = SQA::Strategy::VolumeBreakout.trade(vector)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Characteristics
|
|
38
|
+
|
|
39
|
+
- **Complexity**: Medium
|
|
40
|
+
- **Best Market**: Breakout/trending
|
|
41
|
+
- **Win Rate**: 50-60%
|
|
42
|
+
|
|
43
|
+
## Strengths
|
|
44
|
+
|
|
45
|
+
✅ Volume confirmation reduces false breakouts
|
|
46
|
+
✅ Catches strong moves
|
|
47
|
+
✅ Clear entry points
|
|
48
|
+
|
|
49
|
+
## Weaknesses
|
|
50
|
+
|
|
51
|
+
❌ Rare signals
|
|
52
|
+
❌ Can whipsaw on false breakouts
|
|
53
|
+
❌ Requires both price and volume data
|
|
54
|
+
|