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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54f8ba7f993ae95bf01b2cdeeb32c76b17b02df6799dc046b85fde9b3d54f202
4
- data.tar.gz: 91ea7ae14f99322618c3854f7ac16c4ee79c9a7d39609228d589528c381644df
3
+ metadata.gz: efdd7d63be5b0fd195ed3633a47759c701727e9dafdfd4f457ba6fec91f91426
4
+ data.tar.gz: e0acdaf0f99e81412313e6b1e5bc7de9d884e36e39f0be01c4942aa601e3c916
5
5
  SHA512:
6
- metadata.gz: 7f20d2ed8800c892905e1155006794832af992c7f1309121860e62cc010b26d23af4d04f6e0b03775b4db0a8dbcafca321ea4c0a39ffc7f6533d6f75bbb59976
7
- data.tar.gz: 014345e1802899212fb443bec50783988b535d143f7f8fae50ebbacf4a0a9bf52144d6417b395f342fa0f68d94aceb7878179e9eac2bf429f980af9689dd9249
6
+ metadata.gz: 819b3afd73a08905b5d7047e16604be254821a68f48443740277be3cb2ad0950c59e311d7f41ec2e72a7c0feac698902fec8c3784fdb954a900c55b6dce52523
7
+ data.tar.gz: aeb60130dbfef691da2e561c40d5deacb61e90e0865502a74e3648be279797d3064a383b114f90c898f4327e5881fc7a40f70d70667ee40542a9eca5f5b25b0f
data/bin/sqa CHANGED
@@ -3,4 +3,4 @@
3
3
  require 'sqa'
4
4
  require 'sqa/cli'
5
5
 
6
- SQA::CLI.new.run
6
+ SQA.init
@@ -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
- def initialize
8
- @args = $ARGV.dup
9
- end
10
-
11
- def run
12
- stock = Stock.new('aapl')
13
-
14
- puts <<~OUTPUT
15
-
16
- TBD
17
- @args => #{@args}
18
- stock => #{stock}
19
-
20
- OUTPUT
21
- end
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.from_csv(ticker)
7
- df = SQA::DataFrame.from_csv(ticker)
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,
@@ -8,22 +8,20 @@ class SQA::DataFrame < Daru::DataFrame
8
8
  SQA::Config.data_dir + filename
9
9
  end
10
10
 
11
- def self.from_csv(ticker)
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
- @df = Daru::DataFrame.from_csv(source)
16
+ from_csv(source, options={}, &block)
23
17
  elsif ".json" == type
24
- @df = Daru::DataFrame.from_json(source)
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, "supports csv or json only"
24
+ raise SQA::BadParamenterError, "un-suppod file type: #{type}"
27
25
  end
28
26
  end
29
27
  end
data/lib/sqa/portfolio.rb CHANGED
@@ -3,7 +3,9 @@
3
3
  class SQA::Portfolio
4
4
  attr_accessor :df
5
5
 
6
- def initialize(filename="portfolio.csv")
6
+ def initialize(
7
+ filename = SQA::Config.portfolio_filename
8
+ )
7
9
  @df = SQA::DataFrame.load(filename)
8
10
  end
9
11
  end
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
- @df = klass.send("from_#{type.downcase}", ticker)
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
@@ -4,7 +4,9 @@
4
4
  class SQA::Trade
5
5
  attr_accessor :df
6
6
 
7
- def initialize(filename="trades.csv")
7
+ def initialize(
8
+ filename = SQA::Config.trades_filename
9
+ )
8
10
  @df = SQA::DataFrame.load(filename)
9
11
  end
10
12
 
data/lib/sqa/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module SQA
4
4
  module Version
5
- VERSION = "0.0.5"
5
+ VERSION = "0.0.7"
6
6
  end
7
7
  end
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, HOME + "sqa_data"
40
- default :plotting_library, :gruff
41
- default :lazy_update, false
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.5
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-18 00:00:00.000000000 Z
11
+ date: 2023-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: active_support
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: gruff
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