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