sqa 0.0.5 → 0.0.7
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/bin/sqa +1 -1
- data/checksums/sqa-0.0.6.gem.sha512 +1 -0
- data/docs/data_frame.md +6 -6
- data/docs/libsvm_file_format.md +47 -0
- data/lib/sqa/cli.rb +29 -15
- data/lib/sqa/data_frame/yahoo_finance.rb +6 -2
- data/lib/sqa/data_frame.rb +8 -10
- data/lib/sqa/portfolio.rb +3 -1
- data/lib/sqa/stock.rb +4 -2
- data/lib/sqa/trade.rb +3 -1
- data/lib/sqa/version.rb +1 -1
- data/lib/sqa.rb +24 -3
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: efdd7d63be5b0fd195ed3633a47759c701727e9dafdfd4f457ba6fec91f91426
|
4
|
+
data.tar.gz: e0acdaf0f99e81412313e6b1e5bc7de9d884e36e39f0be01c4942aa601e3c916
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 819b3afd73a08905b5d7047e16604be254821a68f48443740277be3cb2ad0950c59e311d7f41ec2e72a7c0feac698902fec8c3784fdb954a900c55b6dce52523
|
7
|
+
data.tar.gz: aeb60130dbfef691da2e561c40d5deacb61e90e0865502a74e3648be279797d3064a383b114f90c898f4327e5881fc7a40f70d70667ee40542a9eca5f5b25b0f
|
data/bin/sqa
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
b9ac08e43011c8c520b11d157e44e6b3a3ac73e6a81bd76ba6f6d6f0bbbdd113c1a9656f11470670406a3734dd3b337f8f82715c4160693284582c3dc8441a85
|
data/docs/data_frame.md
CHANGED
@@ -13,6 +13,8 @@ There will be Daru extensions and patches made to adapt it to the specific needs
|
|
13
13
|
|
14
14
|
Frankly, Ruby has lost the battle to Python w/r/t data analysis. The Python equivalent library to Daru is Pandas. It is actively maintained. There is a Ruby gem that uses PyCall to access Pandas but it is a few years out of date with open issues.
|
15
15
|
|
16
|
+
I am considering extracting the Daru::DataFrame class into a new gem `sqa-Ddata_frame` so that I can more easily make upgrades and refactor the old thing. It really could use a facelift and a better plugin strategy. The lib/daru/data_frame.rb is over 3,000 lines long. There is a lot of method documentation; but, I not really sure that all of those methods are really needed. We could at least extract each of the methods out into its own file.
|
17
|
+
|
16
18
|
## Creating a DataFrame from a CSV File
|
17
19
|
|
18
20
|
A common activity is to use financial websites such as https://finance.yahoo.com to download historical price data for a stock.
|
@@ -21,6 +23,10 @@ Here is how to create a DataFrame from a CSV file downloaded from Finance.yahoo.
|
|
21
23
|
|
22
24
|
```ruby
|
23
25
|
df = Daru::DataFrame.from_csv('aapl.csv')
|
26
|
+
|
27
|
+
# The SQA way uses the file's type to invoke the
|
28
|
+
# correct method.
|
29
|
+
df = SQA::DataFrame.load(filename)
|
24
30
|
```
|
25
31
|
|
26
32
|
The Daru::DataFrame class can be created from many different sources including an ActiveRecord relation -- e.g. you can get you data from a database.
|
@@ -156,9 +162,3 @@ puts df.ai("Yes; but, should I buy this stock now?")
|
|
156
162
|
```
|
157
163
|
Consulting the magic eight ball cluster.... The future looks cloudy. You should have bought it 14 days ago when I told you it was on its way up! Do you ever listen to me? No! I slave over these numbers night and day. I consult the best magic eight ball sources available. What do I get for my efforts? Nothing!
|
158
164
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# libsvm File Format
|
2
|
+
|
3
|
+
This file format is used by rumale.
|
4
|
+
|
5
|
+
We're choosing the "Adj Close" column as the one that we want to predict.
|
6
|
+
|
7
|
+
The libsvm file format is simple. All values are numberic.
|
8
|
+
|
9
|
+
The first entry on a line is the thing that we want to predict. In this case it is the adjusted closing price. This is followed by a space.
|
10
|
+
|
11
|
+
What follows is a series of data pairs seperated by spaces in the form:
|
12
|
+
|
13
|
+
* index:value
|
14
|
+
|
15
|
+
where index is the column number and value is the value for that item.
|
16
|
+
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
require 'csv'
|
20
|
+
|
21
|
+
# Read CSV file
|
22
|
+
data = CSV.read('input.csv', headers: true)
|
23
|
+
|
24
|
+
# Open output file
|
25
|
+
output_file = File.open('output.txt', 'w')
|
26
|
+
|
27
|
+
# Convert data into libsvm format and write to output file
|
28
|
+
data.each do |row|
|
29
|
+
# Get the label (the "close" value)
|
30
|
+
label = row['Adj Close']
|
31
|
+
|
32
|
+
# Start building the libsvm formatted line
|
33
|
+
libsvm_line = "#{label} "
|
34
|
+
|
35
|
+
# Add feature indices and values
|
36
|
+
row.each_with_index do |(column, value), index|
|
37
|
+
next if column == 'Date' || column == 'Adj Close' # Skip irrelevant columns
|
38
|
+
libsvm_line += "#{index}:#{value} "
|
39
|
+
end
|
40
|
+
|
41
|
+
# Write the libsvm formatted line to the output file
|
42
|
+
output_file.puts(libsvm_line)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Close files
|
46
|
+
output_file.close
|
47
|
+
```
|
data/lib/sqa/cli.rb
CHANGED
@@ -4,21 +4,35 @@ require_relative '../sqa'
|
|
4
4
|
|
5
5
|
module SQA
|
6
6
|
class CLI
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
7
|
+
include Mixlib::CLI
|
8
|
+
|
9
|
+
option :config_file,
|
10
|
+
short: "-c CONFIG",
|
11
|
+
long: "--config CONFIG",
|
12
|
+
default: "~/.sqa.rb",
|
13
|
+
description: "The configuration file to use"
|
14
|
+
|
15
|
+
option :log_level,
|
16
|
+
short: "-l LEVEL",
|
17
|
+
long: "--log_level LEVEL",
|
18
|
+
description: "Set the log level (debug, info, warn, error, fatal)",
|
19
|
+
required: true,
|
20
|
+
in: [:debug, :info, :warn, :error, :fatal],
|
21
|
+
proc: Proc.new { |l| l.to_sym }
|
22
|
+
|
23
|
+
option :help,
|
24
|
+
short: "-h",
|
25
|
+
long: "--help",
|
26
|
+
description: "Show this message",
|
27
|
+
on: :tail,
|
28
|
+
boolean: true,
|
29
|
+
show_options: true,
|
30
|
+
exit: 0
|
31
|
+
|
32
|
+
def run(argv = ARGV)
|
33
|
+
parse_options(argv)
|
34
|
+
SQA::Config.merge!(config)
|
35
|
+
end
|
22
36
|
end
|
23
37
|
end
|
24
38
|
|
@@ -3,9 +3,13 @@
|
|
3
3
|
|
4
4
|
class SQA::DataFrame < Daru::DataFrame
|
5
5
|
class YahooFinance
|
6
|
-
def self.
|
7
|
-
df = SQA::DataFrame.
|
6
|
+
def self.load(filename, options={}, &block)
|
7
|
+
df = SQA::DataFrame.load(filename, options={}, &block)
|
8
8
|
|
9
|
+
# ASSUMPTION: This is the column headers from Yahoo Finance for
|
10
|
+
# CSV files. If the file type is something different from the
|
11
|
+
# same source, they may not be the same.
|
12
|
+
#
|
9
13
|
new_names = {
|
10
14
|
"Date" => :timestamp,
|
11
15
|
"Open" => :open_price,
|
data/lib/sqa/data_frame.rb
CHANGED
@@ -8,22 +8,20 @@ class SQA::DataFrame < Daru::DataFrame
|
|
8
8
|
SQA::Config.data_dir + filename
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.
|
12
|
-
df = super(path("#{ticker.downcase}.csv"))
|
13
|
-
df[:ticker] = ticker
|
14
|
-
df
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.load(filename)
|
11
|
+
def self.load(filename, options={}, &block)
|
18
12
|
source = path(filename)
|
19
13
|
type = source.extname.downcase
|
20
14
|
|
21
15
|
if ".csv" == type
|
22
|
-
|
16
|
+
from_csv(source, options={}, &block)
|
23
17
|
elsif ".json" == type
|
24
|
-
|
18
|
+
from_json(source, options={}, &block)
|
19
|
+
elsif %w[.txt .dat].include?(type)
|
20
|
+
from_plaintext(source, options={}, &block)
|
21
|
+
elsif ".xls" == type
|
22
|
+
from_excel(source, options={}, &block)
|
25
23
|
else
|
26
|
-
raise SQA::BadParamenterError, "
|
24
|
+
raise SQA::BadParamenterError, "un-suppod file type: #{type}"
|
27
25
|
end
|
28
26
|
end
|
29
27
|
end
|
data/lib/sqa/portfolio.rb
CHANGED
data/lib/sqa/stock.rb
CHANGED
@@ -6,10 +6,12 @@ class SQA::Stock
|
|
6
6
|
attr_accessor :ticker
|
7
7
|
|
8
8
|
def initialize(ticker:, source: :yahoo_finance, type: :csv)
|
9
|
-
@ticker = ticker
|
9
|
+
@ticker = ticker.downcase
|
10
10
|
@company_name = "Company Name"
|
11
11
|
klass = "SQA::DataFrame::#{source.to_s.camelize}".constantize
|
12
|
-
|
12
|
+
filename = "#{@ticker}.#{type}"
|
13
|
+
@df = klass.send(:load, filename)
|
14
|
+
@df[:ticker] = ticker
|
13
15
|
end
|
14
16
|
|
15
17
|
def to_s
|
data/lib/sqa/trade.rb
CHANGED
data/lib/sqa/version.rb
CHANGED
data/lib/sqa.rb
CHANGED
@@ -5,6 +5,7 @@ require 'active_support/core_ext/string'
|
|
5
5
|
require 'daru'
|
6
6
|
require 'date'
|
7
7
|
require 'descriptive_statistics'
|
8
|
+
require 'mixlib/cli'
|
8
9
|
require 'mixlib/config'
|
9
10
|
require 'nenv'
|
10
11
|
require 'pathname'
|
@@ -36,19 +37,39 @@ module SQA
|
|
36
37
|
extend Mixlib::Config
|
37
38
|
config_strict_mode true
|
38
39
|
|
39
|
-
default :data_dir,
|
40
|
-
default :plotting_library,
|
41
|
-
default :lazy_update,
|
40
|
+
default :data_dir, HOME + "sqa_data"
|
41
|
+
default :plotting_library, :gruff # TODO: use svg-graph
|
42
|
+
default :lazy_update, false
|
43
|
+
default :portfolio_filename, "portfolio.csv"
|
44
|
+
default :trades_filename, "trades.csv"
|
45
|
+
|
46
|
+
default :log_level, :info
|
47
|
+
default :config_file, "~/.sqa.rb"
|
48
|
+
|
42
49
|
end
|
43
50
|
|
44
51
|
def self.init
|
52
|
+
SQA::CLI.new.run if defined? SQA::CLI
|
53
|
+
|
54
|
+
Config.config_file = Pathname.new homify(Config.config_file)
|
55
|
+
|
56
|
+
Config.from_file(Config.config_file)
|
57
|
+
|
58
|
+
Config.data_dir = Pathname.new homify(Config.data_dir)
|
59
|
+
|
45
60
|
Daru.lazy_update = Config.lazy_update
|
46
61
|
Daru.plotting_library = Config.plotting_library
|
47
62
|
|
48
63
|
nil
|
49
64
|
end
|
65
|
+
|
66
|
+
def self.homify(filepath)
|
67
|
+
filepath.gsub(/^~/, Nenv.home)
|
68
|
+
end
|
50
69
|
end
|
51
70
|
|
71
|
+
# require_relative "patches/daru" # TODO: extract Daru::DataFrame in new gem sqa-data_frame
|
72
|
+
|
52
73
|
require_relative "sqa/data_frame"
|
53
74
|
require_relative "sqa/errors"
|
54
75
|
require_relative "sqa/indicator"
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dewayne VanHoozer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-08-
|
11
|
+
date: 2023-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: mixlib-cli
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -198,6 +198,7 @@ files:
|
|
198
198
|
- checksums/sqa-0.0.3.gem.sha512
|
199
199
|
- checksums/sqa-0.0.4.gem.sha512
|
200
200
|
- checksums/sqa-0.0.5.gem.sha512
|
201
|
+
- checksums/sqa-0.0.6.gem.sha512
|
201
202
|
- docs/README.md
|
202
203
|
- docs/average_true_range.md
|
203
204
|
- docs/bollinger_bands.md
|
@@ -209,6 +210,7 @@ files:
|
|
209
210
|
- docs/fibonacci_retracement.md
|
210
211
|
- docs/head_and_shoulders_pattern.md
|
211
212
|
- docs/identify_wave_condition.md
|
213
|
+
- docs/libsvm_file_format.md
|
212
214
|
- docs/market_profile.md
|
213
215
|
- docs/mean_reversion.md
|
214
216
|
- docs/momentum.md
|