sqa 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|