sqa 0.0.1 → 0.0.3
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/.irbrc +3 -0
- data/checksums/sqa-0.0.2.gem.sha512 +1 -0
- data/docs/average_true_range.md +9 -0
- data/docs/data_frame.md +164 -0
- data/docs/fibonacci_retracement.md +30 -0
- data/docs/identify_wave_condition.md +14 -0
- data/docs/peaks_and_valleys.md +11 -0
- data/docs/requirements.md +22 -0
- data/docs/stochastic_oscillator.md +4 -0
- data/docs/strategy.md +5 -0
- data/lib/sqa/cli.rb +1 -1
- data/lib/sqa/data_frame/yahoo_finance.rb +24 -0
- data/lib/sqa/data_frame.rb +16 -0
- data/lib/sqa/indicator/average_true_range.rb +22 -9
- data/lib/sqa/indicator/bollinger_bands.rb +2 -2
- data/lib/sqa/indicator/candlestick_pattern_recognizer.rb +1 -1
- data/lib/sqa/indicator/donchian_channel.rb +1 -1
- data/lib/sqa/indicator/double_top_bottom_pattern.rb +1 -1
- data/lib/sqa/indicator/elliott_wave_theory.rb +57 -0
- data/lib/sqa/indicator/exponential_moving_average.rb +25 -0
- data/lib/sqa/indicator/exponential_moving_average_trend.rb +36 -0
- data/lib/sqa/indicator/fibonacci_retracement.rb +5 -7
- data/lib/sqa/indicator/head_and_shoulders_pattern.rb +1 -1
- data/lib/sqa/indicator/{classify_market_profile.rb → market_profile.rb} +7 -8
- data/lib/sqa/indicator/mean_reversion.rb +1 -1
- data/lib/sqa/indicator/momentum.rb +9 -7
- data/lib/sqa/indicator/moving_average_convergence_divergence.rb +7 -3
- data/lib/sqa/indicator/peaks_and_valleys.rb +29 -0
- data/lib/sqa/indicator/{relative_strength_index.md.rb → relative_strength_index.rb} +2 -2
- data/lib/sqa/indicator/simple_moving_average.rb +6 -3
- data/lib/sqa/indicator/simple_moving_average_trend.rb +15 -14
- data/lib/sqa/indicator/stochastic_oscillator.rb +32 -3
- data/lib/sqa/indicator/true_range.rb +14 -12
- data/lib/sqa/indicator.rb +4 -4
- data/lib/sqa/stock.rb +6 -13
- data/lib/sqa/strategy.rb +65 -0
- data/lib/sqa/version.rb +3 -1
- data/lib/sqa.rb +44 -6
- metadata +34 -29
- data/lib/sqa/datastore/active_record.rb +0 -89
- data/lib/sqa/datastore/csv/yahoo_finance.rb +0 -51
- data/lib/sqa/datastore/csv.rb +0 -93
- data/lib/sqa/datastore/sqlite.rb +0 -7
- data/lib/sqa/datastore.rb +0 -6
- data/lib/sqa/indicator/average_true_range.md +0 -9
- data/lib/sqa/indicator/ema_analysis.rb +0 -70
- data/lib/sqa/indicator/fibonacci_retracement.md +0 -3
- data/lib/sqa/indicator/identify_wave_condition.md +0 -6
- data/lib/sqa/indicator/identify_wave_condition.rb +0 -40
- data/lib/sqa/indicator/stochastic_oscillator.md +0 -5
- /data/{lib/sqa/indicator → docs}/README.md +0 -0
- /data/{lib/sqa/indicator → docs}/bollinger_bands.md +0 -0
- /data/{lib/sqa/indicator → docs}/candlestick_pattern_recognizer.md +0 -0
- /data/{lib/sqa/indicator → docs}/donchian_channel.md +0 -0
- /data/{lib/sqa/indicator → docs}/double_top_bottom_pattern.md +0 -0
- /data/{lib/sqa/indicator/ema_analysis.md → docs/exponential_moving_average.md} +0 -0
- /data/{lib/sqa/indicator → docs}/head_and_shoulders_pattern.md +0 -0
- /data/{lib/sqa/indicator/classify_market_profile.md → docs/market_profile.md} +0 -0
- /data/{lib/sqa/indicator → docs}/mean_reversion.md +0 -0
- /data/{lib/sqa/indicator → docs}/momentum.md +0 -0
- /data/{lib/sqa/indicator → docs}/moving_average_convergence_divergence.md +0 -0
- /data/{lib/sqa/indicator → docs}/relative_strength_index.md +0 -0
- /data/{lib/sqa/indicator → docs}/simple_moving_average.md +0 -0
- /data/{lib/sqa/indicator → docs}/true_range.md +0 -0
@@ -1,51 +0,0 @@
|
|
1
|
-
# lib/sqa/datastore/csv/yahoo_finance.rb
|
2
|
-
|
3
|
-
# processes a CSV file downloaded from finance.yahoo.com
|
4
|
-
# Date,Open,High,Low,Close,Adj Close,Volume
|
5
|
-
|
6
|
-
require 'csv-importer'
|
7
|
-
|
8
|
-
class SQA::Datastore::CSV::YahooFinance
|
9
|
-
include CSVImporter
|
10
|
-
|
11
|
-
model ::SQA::Activity # an active record like model
|
12
|
-
|
13
|
-
column :date, to: ->(x) { Date.parse(x)}, required: true
|
14
|
-
column :open, to: ->(x) {x.to_f}, required: true
|
15
|
-
column :high, to: ->(x) {x.to_f}, required: true
|
16
|
-
column :low, to: ->(x) {x.to_f}, required: true
|
17
|
-
column :close, to: ->(x) {x.to_f}, required: true
|
18
|
-
column :adj_close, to: ->(x) {x.to_f}, required: true
|
19
|
-
column :volumn, to: ->(x) {x.to_i}, required: true
|
20
|
-
|
21
|
-
# TODO: make the identifier compound [ticker, date]
|
22
|
-
# so we can put all the data into a single table.
|
23
|
-
|
24
|
-
identifier :date
|
25
|
-
|
26
|
-
when_invalid :skip # or :abort
|
27
|
-
|
28
|
-
|
29
|
-
column :email, to: ->(email) { email.downcase }, required: true
|
30
|
-
column :first_name, as: [ /first.?name/i, /pr(é|e)nom/i ]
|
31
|
-
column :last_name, as: [ /last.?name/i, "nom" ]
|
32
|
-
column :published, to: ->(published, user) { user.published_at = published ? Time.now : nil }
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
def self.load(ticker)
|
38
|
-
import = new(file: "#{ticker.upcase}.csv")
|
39
|
-
|
40
|
-
import.valid_header? # => false
|
41
|
-
import.report.message # => "The following columns are required: email"
|
42
|
-
|
43
|
-
# Assuming the header was valid, let's run the import!
|
44
|
-
|
45
|
-
import.run!
|
46
|
-
import.report.success? # => true
|
47
|
-
import.report.message # => "Import completed. 4 created, 2 updated, 1 failed to update" end
|
48
|
-
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
data/lib/sqa/datastore/csv.rb
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
# lib/sqa/datastore/csv.rb
|
2
|
-
|
3
|
-
require 'csv'
|
4
|
-
require 'forwardable'
|
5
|
-
|
6
|
-
module SQA::Datastore
|
7
|
-
class CSV
|
8
|
-
extend Forwardable
|
9
|
-
def_delegators :@data, :first, :last, :size, :empty?, :[], :map, :select, :reject
|
10
|
-
|
11
|
-
SOURCE_DOMAIN = "https://query1.finance.yahoo.com/v7/finance/download/"
|
12
|
-
# curl -o AAPL.csv -L --url "https://query1.finance.yahoo.com/v7/finance/download/AAPL?period1=345427200&period2=1691712000&interval=1d&events=history&includeAdjustedClose=true"
|
13
|
-
|
14
|
-
|
15
|
-
attr_accessor :ticker
|
16
|
-
attr_accessor :data
|
17
|
-
|
18
|
-
def initialize(ticker, adapter = YahooFinance)
|
19
|
-
@ticker = ticker
|
20
|
-
@data_path = Pathname.pwd + "#{ticker.downcase}.csv"
|
21
|
-
@adapter = adapter
|
22
|
-
@data = adapter.load(ticker)
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
#######################################################################
|
27
|
-
# Read the CSV file associated with the give ticker symbol
|
28
|
-
#
|
29
|
-
# def read_csv_data
|
30
|
-
# download_historical_prices unless @data_path.exist?
|
31
|
-
|
32
|
-
# csv_data = []
|
33
|
-
|
34
|
-
# ::CSV.foreach(@data_path, headers: true) do |row|
|
35
|
-
# csv_data << row.to_h
|
36
|
-
# end
|
37
|
-
|
38
|
-
# csv_data
|
39
|
-
# end
|
40
|
-
|
41
|
-
#######################################################################
|
42
|
-
# download a CSV file from https://query1.finance.yahoo.com
|
43
|
-
# given a stock ticker symbol as a String
|
44
|
-
# start and end dates
|
45
|
-
#
|
46
|
-
# For ticker "aapl" the downloaded file will be named "aapl.csv"
|
47
|
-
# That filename will be renamed to "aapl_YYYYmmdd.csv" where the
|
48
|
-
# date suffix is the end_date of the historical data.
|
49
|
-
#
|
50
|
-
# def download_historical_prices(
|
51
|
-
# start_date: Date.new(2019, 1, 1),
|
52
|
-
# end_date: previous_dow(:friday, Date.today)
|
53
|
-
# )
|
54
|
-
|
55
|
-
# start_timestamp = start_date.to_time.to_i # Convert to unix timestamp
|
56
|
-
# end_timestamp = end_date.to_time.to_i
|
57
|
-
|
58
|
-
# user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0"
|
59
|
-
|
60
|
-
# # TODO: replace curl with Faraday
|
61
|
-
|
62
|
-
# `curl -A "#{user_agent}" --cookie-jar cookies.txt -o #{@data_path} -L --url "#{SOURCE_DOMAIN}/#{ticker.upcase}?period1=#{start_timestamp}&period2=#{end_timestamp}&interval=1d&events=history&includeAdjustedClose=true"`
|
63
|
-
|
64
|
-
# check_csv_file
|
65
|
-
# end
|
66
|
-
|
67
|
-
|
68
|
-
# def check_csv_file
|
69
|
-
# f = File.open(@data_path, 'r')
|
70
|
-
# c1 = f.read(1)
|
71
|
-
|
72
|
-
# if '{' == c1
|
73
|
-
# error_msg = JSON.parse("#{c1}#{f.read}")
|
74
|
-
# raise "Not OK: #{error_msg}"
|
75
|
-
# end
|
76
|
-
# end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
__END__
|
81
|
-
|
82
|
-
{
|
83
|
-
"finance": {
|
84
|
-
"error": {
|
85
|
-
"code": "Unauthorized",
|
86
|
-
"description": "Invalid cookie"
|
87
|
-
}
|
88
|
-
}
|
89
|
-
}
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
data/lib/sqa/datastore/sqlite.rb
DELETED
data/lib/sqa/datastore.rb
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
# Average True Range
|
2
|
-
|
3
|
-
Calculates the Average True Range (ATR) for a given set of price data.
|
4
|
-
|
5
|
-
The Average True Range is an indicator that calculates the average of the True Range values over a specified period. It provides a measure of the average volatility of a security over that period.
|
6
|
-
|
7
|
-
The ATR is commonly used to assess the volatility of a security, identify potential trend reversals, and determine appropriate stop-loss levels. Higher ATR values indicate higher volatility, while lower ATR values indicate lower volatility.
|
8
|
-
|
9
|
-
For example, a 14-day Average True Range would calculate the average of the True Range values over the past 14 trading days. Traders and analysts may use this indicator to set stop-loss levels based on the average volatility of the security.
|
@@ -1,70 +0,0 @@
|
|
1
|
-
# lib/sqa/indicator/ema_analysis.rb
|
2
|
-
|
3
|
-
module SQA::Indicator; class << self
|
4
|
-
|
5
|
-
def ema_analysis(
|
6
|
-
prices, # Array of prices
|
7
|
-
period # Integer number of entries to consider
|
8
|
-
)
|
9
|
-
return {} if prices.empty? || period <= 0
|
10
|
-
|
11
|
-
ema_values = []
|
12
|
-
ema_values << prices.first
|
13
|
-
|
14
|
-
multiplier = (2.0 / (period + 1))
|
15
|
-
|
16
|
-
(1...prices.length).each do |i|
|
17
|
-
ema = (prices[i] - ema_values.last) * multiplier + ema_values.last
|
18
|
-
ema_values << ema.round(2)
|
19
|
-
end
|
20
|
-
|
21
|
-
analysis = {}
|
22
|
-
|
23
|
-
analysis[:ema_values] = ema_values
|
24
|
-
analysis[:trend] = ema_determine_trend(ema_values)
|
25
|
-
analysis[:support] = ema_determine_support(ema_values)
|
26
|
-
analysis[:resistance] = ema_determine_resistance(ema_values)
|
27
|
-
|
28
|
-
analysis
|
29
|
-
end
|
30
|
-
|
31
|
-
|
32
|
-
# @param ema_values [Array] An array of EMA values.
|
33
|
-
# @return [Symbol] The trend: :up, :down, or :sideways.
|
34
|
-
#
|
35
|
-
private def ema_determine_trend(ema_values)
|
36
|
-
return :sideways if ema_values.empty?
|
37
|
-
|
38
|
-
last_ema = ema_values.last
|
39
|
-
previous_ema = ema_values[-2]
|
40
|
-
|
41
|
-
if last_ema > previous_ema
|
42
|
-
:up
|
43
|
-
elsif last_ema < previous_ema
|
44
|
-
:down
|
45
|
-
else
|
46
|
-
:sideways
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
|
51
|
-
# @param ema_values [Array] An array of EMA values.
|
52
|
-
# @return [Float] The support level.
|
53
|
-
#
|
54
|
-
private def ema_determine_support(ema_values)
|
55
|
-
return 0.0 if ema_values.empty?
|
56
|
-
|
57
|
-
ema_values.min
|
58
|
-
end
|
59
|
-
|
60
|
-
|
61
|
-
# @param ema_values [Array] An array of EMA values.
|
62
|
-
# @return [Float] The resistance level.
|
63
|
-
private def ema_determine_resistance(ema_values)
|
64
|
-
return 0.0 if ema_values.empty?
|
65
|
-
|
66
|
-
ema_values.max
|
67
|
-
end
|
68
|
-
|
69
|
-
end; end
|
70
|
-
|
@@ -1,6 +0,0 @@
|
|
1
|
-
# Wave Theory
|
2
|
-
|
3
|
-
Wave theory, such as Elliott Wave Theory, suggests that price movements follow repetitive patterns or waves. It aims to identify and predict these patterns to make trading decisions.
|
4
|
-
|
5
|
-
Identifies a wave condition in a stock's price history based on a given price series.
|
6
|
-
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# lib/sqa/indicator/identify_wave_condition.rb
|
2
|
-
|
3
|
-
module SQA::Indicator; class << self
|
4
|
-
|
5
|
-
def identify_wave_condition?(
|
6
|
-
prices, # Array of prices
|
7
|
-
wave_length, # Integer expected length of a wave pattern
|
8
|
-
tolerance # Float delta change in price that would indicate a wave
|
9
|
-
)
|
10
|
-
return false if prices.length < wave_length
|
11
|
-
|
12
|
-
wave_start = 0
|
13
|
-
wave_end = wave_length - 1
|
14
|
-
|
15
|
-
while wave_end < prices.length
|
16
|
-
wave = prices[wave_start..wave_end]
|
17
|
-
|
18
|
-
if wave.length == wave_length &&
|
19
|
-
wave_pattern?(wave, tolerance)
|
20
|
-
return true
|
21
|
-
end
|
22
|
-
|
23
|
-
wave_start += 1
|
24
|
-
wave_end += 1
|
25
|
-
end
|
26
|
-
|
27
|
-
false
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
private def wave_pattern?(wave, tolerance)
|
32
|
-
wave.each_cons(2) do |a, b|
|
33
|
-
return false if (b - a).abs > tolerance
|
34
|
-
end
|
35
|
-
|
36
|
-
true
|
37
|
-
end
|
38
|
-
|
39
|
-
end; end
|
40
|
-
|
@@ -1,5 +0,0 @@
|
|
1
|
-
# Stochastic Oscillator
|
2
|
-
|
3
|
-
Calculates the Stochastic Oscillator for a given set of price data.
|
4
|
-
|
5
|
-
Stochastic Oscillator: The Stochastic Oscillator compares a security's closing price to its price range over a specified period. It helps identify potential trend reversals and overbought/oversold conditions.
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|