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,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
|
+
- [Trading with RSI](../concepts/momentum.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
|
+
|
data/docs/tags.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Technical Market Analysis: Understanding the True Strength Index (TSI)
|
|
2
|
+
|
|
3
|
+
The **True Strength Index (TSI)** is a technical momentum oscillator used to identify trends and reversals primarily in the price of a security. It is not directly related to the Relative Strength Index (RSI), although both are momentum indicators.
|
|
4
|
+
|
|
5
|
+
## How TSI is Calculated
|
|
6
|
+
|
|
7
|
+
The TSI formula is based on double smoothing of price changes:
|
|
8
|
+
|
|
9
|
+
1. **Calculate the Price Momentum**:
|
|
10
|
+
- Determine the daily price change: Current price minus previous price.
|
|
11
|
+
- Create a 25-period Exponential Moving Average (EMA) of price changes (this period can vary based on the trader's preference).
|
|
12
|
+
|
|
13
|
+
2. **Calculate the Absolute Price Momentum**:
|
|
14
|
+
- Calculate the absolute value of the daily price change.
|
|
15
|
+
- Create a 25-period EMA of the absolute price changes.
|
|
16
|
+
|
|
17
|
+
3. **Apply a Secondary Smoothing**:
|
|
18
|
+
- Calculate a 13-period EMA of the 25-period EMA of price changes.
|
|
19
|
+
- Calculate a 13-period EMA of the 25-period EMA of the absolute price changes.
|
|
20
|
+
|
|
21
|
+
4. **The TSI Formula**:
|
|
22
|
+
- TSI = 100 x (Double Smoothed Price Change / Double Smoothed Absolute Price Change)
|
|
23
|
+
|
|
24
|
+
The most common settings for the TSI are the 25-period EMA for initial smoothing and the 13-period EMA for the second smoothing. These periods can be adjusted to suit different trading styles and timeframes.
|
|
25
|
+
|
|
26
|
+
## How to Interpret TSI
|
|
27
|
+
|
|
28
|
+
- **Centerline Crossover**:
|
|
29
|
+
- When the TSI crosses above the centerline (0), it is considered bullish.
|
|
30
|
+
- When it crosses below the centerline, it is considered bearish.
|
|
31
|
+
|
|
32
|
+
- **Signal Line Crossover**:
|
|
33
|
+
- Traders often add a signal line, which is an EMA of the TSI (commonly a 7-period EMA).
|
|
34
|
+
- A bullish signal is generated when the TSI crosses above the signal line.
|
|
35
|
+
- A bearish signal is generated when TSI crosses below the signal line.
|
|
36
|
+
|
|
37
|
+
- **Overbought / Oversold Conditions**:
|
|
38
|
+
- The TSI can indicate overbought or oversold conditions. However, unlike RSI, there are no standard levels, such as 70 or 30, to indicate these conditions in TSI.
|
|
39
|
+
- Traders often observe extreme levels or divergence with the price to identify possible reversals.
|
|
40
|
+
|
|
41
|
+
- **Divergences**:
|
|
42
|
+
- Bullish divergence occurs if the price is making new lows while the TSI is failing to make new lows.
|
|
43
|
+
- Bearish divergence occurs if the price is making new highs while the TSI is failing to make new highs.
|
|
44
|
+
|
|
45
|
+
The TSI can be a valuable tool in your technical analysis toolkit. It helps to smooth out the volatility inherent in the market and provides a clearer picture of the price momentum. As with any technical indicator, it is advisable to use the TSI in conjunction with other tools and analysis methods to confirm signals and make informed trading decisions.
|
|
46
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
## Weighted Moving Average (WMA)
|
|
2
|
+
|
|
3
|
+
### What is a Weighted Moving Average?
|
|
4
|
+
|
|
5
|
+
A Weighted Moving Average (WMA) is a type of moving average that assigns more importance to recent prices by giving them greater weights. Unlike a simple moving average (SMA) that treats all values equally, a WMA emphasizes the latest data points, thus responding more quickly to price changes.
|
|
6
|
+
|
|
7
|
+
### How is a WMA Calculated?
|
|
8
|
+
|
|
9
|
+
To calculate a WMA, you follow these steps:
|
|
10
|
+
|
|
11
|
+
1. Choose the number of periods (n) for the average.
|
|
12
|
+
2. Assign weights to each price point, with the most recent price having the highest weight and the oldest price having the lowest. Weights typically decrement by 1 - for example, starting from n down to 1.
|
|
13
|
+
3. Multiply each price by its corresponding weight.
|
|
14
|
+
4. Sum up the weighted prices.
|
|
15
|
+
5. Divide the sum by the total of the weights.
|
|
16
|
+
|
|
17
|
+
The formula for WMA is:
|
|
18
|
+
|
|
19
|
+
WMA = (Price_n * Weight_n + Price_(n-1) * Weight_(n-1) + ... + Price_1 * Weight_1) / (Weight_n + Weight_(n-1) + ... + Weight_1)
|
|
20
|
+
|
|
21
|
+
Where:
|
|
22
|
+
- Price_n is the most recent price,
|
|
23
|
+
- Weight_n is the weight for the most recent price (usually equal to n).
|
|
24
|
+
|
|
25
|
+
### Using a Weighted Moving Average in Technical Analysis
|
|
26
|
+
|
|
27
|
+
A WMA is used in technical stock market analysis to smooth out price data and help identify trends. Here are some common uses:
|
|
28
|
+
|
|
29
|
+
1. **Trend Identification**: An upward sloping WMA indicates an uptrend, while a downward sloping WMA suggests a downtrend.
|
|
30
|
+
|
|
31
|
+
2. **Support and Resistance**: A WMA can act as a potential support or resistance level. Prices often bounce off the WMA line or struggle to break through it.
|
|
32
|
+
|
|
33
|
+
3. **Crossover Signals**: The crossover of a short-term WMA above a long-term WMA may signal a bullish trend, and vice versa for a bearish trend.
|
|
34
|
+
|
|
35
|
+
4. **Enhanced Reaction**: WMAs can provide quicker signals than simple moving averages due to their greater emphasis on recent prices, which is useful for short-term traders looking for prompt entry or exit points.
|
|
36
|
+
|
|
37
|
+
5. **Confluence with Other Indicators**: Traders often use WMAs in conjunction with other indicators, such as the Relative Strength Index (RSI) or Moving Average Convergence Divergence (MACD), to confirm signals or gain additional insights into market momentum.
|
|
38
|
+
|
|
39
|
+
### Limitations of Weighted Moving Averages
|
|
40
|
+
|
|
41
|
+
1. **Lagging Indicator**: While WMAs are designed to be more responsive than simple moving averages, they are still lagging indicators and might give signals after a trend has already begun.
|
|
42
|
+
|
|
43
|
+
2. **Noise**: In highly volatile markets, the WMA might be too reactive to price changes, resulting in false signals.
|
|
44
|
+
|
|
45
|
+
3. **Subjectivity**: The choice of the period and weight assignment can be subjective and significantly impact the analysis outcomes.
|
|
46
|
+
|
|
47
|
+
Traders should consider these limitations and ideally combine the WMA with other forms of analysis to make informed trading decisions.
|
|
48
|
+
|