sqa 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48ca0637f3792531412ee5d07c2fd49a28f167a04f797d535a5d81e8b47907fb
4
- data.tar.gz: e03b6c57017dab18c86a7e162ee4f9ff8c19567df92b29b0f132349959f802a9
3
+ metadata.gz: 0f6d2b8e3a8092a5c423c86ebb5a2058d3d1ce9b1f617084009dcb63600fdc88
4
+ data.tar.gz: 1b26d1cd8cc77d50567e20cd939c99d103b877681c65dd0cfa72a08feec55ae4
5
5
  SHA512:
6
- metadata.gz: 5d373732f21ea218e6b2614cd8ef45d93e23e59dbfada17bded86974559c0ca4a99426bcf131ddbd5a6286edbd27e7212f1fbe9c8c3ceaa6eeca1ef9b4888451
7
- data.tar.gz: b1c2b23bc8abd33c20c1337481c6f8e51243fe946fd6738f4cdea4f3f0c746233730f4b3cfc13710fc0f9e11dce0b248d22acfb08b21a7200599edc3a7b12a4f
6
+ metadata.gz: f6f3691cfe84cab52cd2001151e8fdcd2b23951466349b1285c7120b3a170906aa197194d08312f032090659748667393d182fe1e7c69e65a124361d48dc4b44
7
+ data.tar.gz: 3a9229b9a64d3306efe90b9bc364c39ef1042ff549709447888df6db9c6c9fbe469a767d1dce667b91edca6b0b80f2df609effe2b3ce7be009d8db14415d28ed
@@ -0,0 +1 @@
1
+ 0bf41b69d8f760412a87aa119292b29f8d23c1a09daf059643314cb00fc251a5bd88a4843d9ed9e2493a9b177389a4bba2b7aff998d90bc7b50b81fb9fd81e47
@@ -0,0 +1 @@
1
+ e63dcb48ad13d1d8397b5445e25d15e58ede7191e6b9f5c5a106d701a01020036eb37cc1b45954d7fb7aa819527452df7b16b82678f439b138833c8ad0377dec
data/lib/sqa/errors.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # lib/sqa/errors.rb
2
2
 
3
3
  module SQA
4
+ # raised when an API contract is broken
4
5
  class BadParameterError < ArgumentError; end
5
6
  end
@@ -0,0 +1,38 @@
1
+ # lib/sqa/strategry/common.rb
2
+
3
+ # This module needs to be extend'ed within
4
+ # a strategy class so that these common class
5
+ # methods are available in every trading strategy.
6
+
7
+ class SQA::Strategy
8
+ module Common
9
+ def trade_against(vector)
10
+ return :hold unless respond_to? :trade
11
+
12
+ recommendation = trade(vector)
13
+
14
+ if :sell == recommendation
15
+ :buy
16
+ elsif :buy == recommendation
17
+ :sell
18
+ else
19
+ :hold
20
+ end
21
+ end
22
+
23
+ def desc
24
+ doc_filename = self.name.split('::').last.downcase + ".md"
25
+ doc_path = Pathname.new(__dir__) + doc_filename
26
+
27
+ debug_me{[ :doc_path ]}
28
+
29
+ if doc_path.exist?
30
+ doc = doc_path.read
31
+ else
32
+ doc = "A description of #{self.name} is not available"
33
+ end
34
+
35
+ puts doc
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,43 @@
1
+ # lib/sqa/strategry/consensus.rb
2
+
3
+ require_relative 'common'
4
+
5
+ class SQA::Strategy::Consensus
6
+ extend SQA::Strategy::Common
7
+
8
+ def self.trade(vector)
9
+ new(vector).my_fancy_trader
10
+ end
11
+
12
+ def initialize(vector)
13
+ @vector = vector
14
+ @results = []
15
+ end
16
+
17
+ def my_fancy_trader
18
+ strat_one
19
+ strat_two
20
+ strat_three
21
+ strat_four
22
+ strat_five
23
+ consensus
24
+ end
25
+
26
+ def consensus
27
+ count = @results.group_by(&:itself).transform_values(&:count)
28
+
29
+ if count[:buy] > count[:sell]
30
+ :buy
31
+ elsif count[:sell] > count[:buy]
32
+ :sell
33
+ else
34
+ :hold
35
+ end
36
+ end
37
+
38
+ def strat_one = @results << (0==rand(2) ? :buy : :sell)
39
+ def strat_two = @results << (0==rand(2) ? :buy : :sell)
40
+ def strat_three = @results << (0==rand(2) ? :buy : :sell)
41
+ def strat_four = @results << (0==rand(2) ? :buy : :sell)
42
+ def strat_five = @results << :hold
43
+ end
@@ -0,0 +1,19 @@
1
+ # lib/sqa/strategry/ema.rb
2
+
3
+ require_relative 'common'
4
+
5
+ class SQA::Strategy::EMA
6
+ extend SQA::Strategy::Common
7
+
8
+ def self.trade(vector)
9
+ ema_trend = vector.ema[:trend]
10
+
11
+ if :up == ema_trend
12
+ :buy
13
+ elsif :down == ema_trend
14
+ :sell
15
+ else
16
+ :hold
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # lib/sqa/strategry/mp.rb
2
+
3
+ require_relative 'common'
4
+
5
+ class SQA::Strategy::MP
6
+ extend SQA::Strategy::Common
7
+
8
+ def self.trade(vector)
9
+ mp = vector.market_profile=:mixed,
10
+
11
+ if :resistance == mp
12
+ :sell
13
+ elsif :support == mp
14
+ :buy
15
+ else
16
+ :hold
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ # lib/sqa/strategry/mr.rb
2
+
3
+ require_relative 'common'
4
+
5
+ class SQA::Strategy::MR
6
+ extend SQA::Strategy::Common
7
+
8
+ def self.trade(vector)
9
+ if vector.mr
10
+ :sell
11
+ else
12
+ :hold
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ # SQA::Strategy::Random
2
+
3
+ A random flip of a three headed coin.
4
+
5
+ Responds with a :buy, :sell or :hold recommendation based upon a random number. Out of 9 possible random numbers, the lower third, middle third and upper third of the number set are used to determine the recommendation.
@@ -0,0 +1,18 @@
1
+ # lib/sqa/strategry/random.rb
2
+
3
+ require_relative 'common'
4
+
5
+ class SQA::Strategy::Random
6
+ extend SQA::Strategy::Common
7
+
8
+ def self.trade(vector)
9
+ case rand(9)
10
+ when (0..2)
11
+ :buy
12
+ when (3..5)
13
+ :sell
14
+ else
15
+ :hold
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ # lib/sqa/strategry/rsi.rb
2
+
3
+ require_relative 'common'
4
+
5
+ class SQA::Strategy::RSI
6
+ extend SQA::Strategy::Common
7
+
8
+ def self.trade(vector)
9
+ rsi_trend = vector.rsi[:trend]
10
+
11
+ if :over_bought == rsi_trend
12
+ :sell
13
+ elsif :over_sold == rsi_trend
14
+ :buy
15
+ else
16
+ :hold
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # lib/sqa/strategry/sma.rb
2
+
3
+ require_relative 'common'
4
+
5
+ class SQA::Strategy::SMA
6
+ extend SQA::Strategy::Common
7
+
8
+ def self.trade(vector)
9
+ sma_trend = vector.rsi[:trend]
10
+
11
+ if :up == sma_trend
12
+ :buy
13
+ elsif :down == sma_trend
14
+ :sell
15
+ else
16
+ :hold
17
+ end
18
+ end
19
+ end
data/lib/sqa/strategy.rb CHANGED
@@ -7,9 +7,16 @@ class SQA::Strategy
7
7
  @strategies = []
8
8
  end
9
9
 
10
- def add(a_proc=nil, &block)
11
- @strategies << a_proc unless a_proc.nil?
12
- @strategies << block if a_proc.nil? && block_given?
10
+ def add(a_strategy)
11
+ raise SQA::BadParameterError unless [Class, Method].include? a_strategy.class
12
+
13
+ a_proc = if Class == a_strategy.class
14
+ a_strategy.method(:trade)
15
+ else
16
+ a_strategy
17
+ end
18
+
19
+ @strategies << a_proc
13
20
  end
14
21
 
15
22
  def execute(v)
@@ -18,48 +25,33 @@ class SQA::Strategy
18
25
  @strategies.each { |signal| result << signal.call(v) }
19
26
  result
20
27
  end
21
- end
22
28
 
23
- __END__
29
+ def auto_load(except: [:common], only: [])
30
+ dir_path = Pathname.new(__dir__) + "strategy"
31
+ except = Array(except).map{|f| f.to_s.downcase}
32
+ only = Array(only).map{|f| f.to_s.downcase}
24
33
 
25
- Example Usage
26
- =============
34
+ dir_path.children.each do |child|
35
+ next unless ".rb" == child.extname.downcase
27
36
 
28
- ss = SQA::Strategy.new
37
+ basename = child.basename.to_s.split('.').first.downcase
29
38
 
30
- ss.add do |vector|
31
- case rand(10)
32
- when (8..)
33
- :buy
34
- when (..3)
35
- :sell
36
- else
37
- :hold
38
- end
39
- end
39
+ next if except.include? basename
40
+ next if !only.empty? && !only.include?(basename)
40
41
 
42
+ print "loading #{basename} ... "
43
+ load child
44
+ puts "done"
45
+ end
41
46
 
42
- ss.add do |vector|
43
- case rand(10)
44
- when (8..)
45
- :sell
46
- when (..3)
47
- :buy
48
- else
49
- :keep
47
+ nil
50
48
  end
51
- end
52
-
53
- def magic(vector)
54
- 0 == rand(2) ? :spend : :save
55
- end
56
49
 
57
- ss.add method(:magic)
58
-
59
- class MyClass
60
- def self.my_method(vector)
61
- vector.rsi[:rsi]
50
+ def available
51
+ ObjectSpace.each_object(Class).select { |klass|
52
+ klass.to_s.start_with?("SQA::Strategy::")
53
+ }
62
54
  end
63
55
  end
64
56
 
65
- ss.add MyClass.method(:my_method)
57
+
@@ -0,0 +1,54 @@
1
+ # Trading Strategies
2
+
3
+ A **strategy** is implemented as a class within the namespace of SQA::Strategy -- see the file lib/sqa/strategy/random.rb as an example. All strategy classes should have a class method **trade** which is the primary entry point into the strategy. The class can be extended using the SQA::Strategy::Common module which adds common class methods such as **trade_against** and **desc**
4
+
5
+ ## The **trade** Class Method
6
+
7
+ The method accepts a single parameter called a vector. The vector parameter is an object that contains the information required by the strategy in order to make a recommendation. In the examples provided this object is an OpenStruct. You can either follow this pattern or use your own; however, at this time only one parameter is allowed for the trade method.
8
+
9
+ ## The **trade_against** Class Method
10
+
11
+ If **trade** is consistently wrong many more times than it is right, don't throw it out. Just start using the **trade_against** class method instead. This method takes the recommendation of the **trade** class method and suggests the opposite.
12
+
13
+ ## The **desc** Class Method
14
+
15
+ You can document your strategy in a markdown formatted file. The **desc** class method will look for the filename in the same directory as the strategy file. This is typically in the lib/sqa/strategy directory.
16
+
17
+ The **desc** class method will find the markdown file and return its contents as a String so that you can do with it as you please.
18
+
19
+ ## Example Strategies
20
+
21
+ The follow examples are provided:
22
+
23
+ * ema.rb
24
+ * mp.rb
25
+ * mr.rb
26
+ * random.rb
27
+ * rsi.rb
28
+ * sma.rb
29
+
30
+ ## Usage
31
+
32
+ Tge SQA::Strategy class manages an Array of trading strategies. You can add to the Array multiple strategies like this:
33
+
34
+ ```ruby
35
+ require 'sqa'
36
+ ss = SQA::Strategy.new
37
+ ss.add SQA::Strategy::Random.method(:trade)
38
+ ss.add SQA::Strategy::SMA.method(:trade)
39
+ ss.add SQA::Strategy::EMA
40
+ ```
41
+
42
+ Note that if your primary entry point to the trading strategy class is **trade** then the parameter to the **add** function does not have to include the ".method(:entry_point)" -- just use the class name by itself. If you do not use **trade** as as class method in you strategy class, then the **trade_against** method added by the SQA::Strategy::Common module will not work.
43
+
44
+ If you want to evaluate the **trade_against** class method in a strategy then you must the "ss.add SQA::Strategy::Random.method(:trade_against)" pattern.
45
+
46
+ Then for any specific stock create your vector object that contains all the information that the trading strategies need in order to make their recommendations. Once you have you vector you can then **execute** the Array of strategies.
47
+
48
+ ```ruby
49
+ vector = ...
50
+ result = ss.execute(vector)
51
+ ```
52
+
53
+ **result** will be an Array of recommendations from the different strategies on whether to :bur, :sell or :hold.
54
+
data/lib/sqa/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module SQA
4
4
  module Version
5
- VERSION = "0.0.3"
5
+ VERSION = "0.0.4"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sqa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dewayne VanHoozer
@@ -20,7 +20,6 @@ extensions: []
20
20
  extra_rdoc_files: []
21
21
  files:
22
22
  - ".envrc"
23
- - ".irbrc"
24
23
  - CHANGELOG.md
25
24
  - LICENSE
26
25
  - README.md
@@ -28,6 +27,8 @@ files:
28
27
  - bin/sqa
29
28
  - checksums/sqa-0.0.1.gem.sha512
30
29
  - checksums/sqa-0.0.2.gem.sha512
30
+ - checksums/sqa-0.0.3.gem.sha512
31
+ - checksums/sqa-0.0.4.gem.sha512
31
32
  - docs/README.md
32
33
  - docs/average_true_range.md
33
34
  - docs/bollinger_bands.md
@@ -80,6 +81,16 @@ files:
80
81
  - lib/sqa/protfolio.rb
81
82
  - lib/sqa/stock.rb
82
83
  - lib/sqa/strategy.rb
84
+ - lib/sqa/strategy/common.rb
85
+ - lib/sqa/strategy/consensus.rb
86
+ - lib/sqa/strategy/ema.rb
87
+ - lib/sqa/strategy/mp.rb
88
+ - lib/sqa/strategy/mr.rb
89
+ - lib/sqa/strategy/random.md
90
+ - lib/sqa/strategy/random.rb
91
+ - lib/sqa/strategy/rsi.rb
92
+ - lib/sqa/strategy/sma.rb
93
+ - lib/sqa/strategyREADME.md
83
94
  - lib/sqa/version.rb
84
95
  homepage: https://github.com/MadBomber/sqa
85
96
  licenses:
data/.irbrc DELETED
@@ -1,3 +0,0 @@
1
- # sqa/,urg
2
-
3
- require 'sqa'