iron_warbler 2.0.7.39 → 2.0.7.40
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/app/controllers/iro/api/stocks_controller.rb +16 -1
- data/app/controllers/iro/api_controller.rb +10 -0
- data/app/controllers/iro/stocks_controller.rb +22 -1
- data/app/models/iro/option.rb +49 -1
- data/app/models/iro/priceitem.rb +7 -1
- data/app/models/tda/option.rb +21 -10
- data/app/views/iro/api/stocks/max_pain.json.jbuilder +18 -0
- data/app/views/iro/stocks/show.haml +3 -1
- data/config/routes.rb +7 -6
- data/lib/tasks/test_tasks.rake +8 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9f3f78d3df3906d30951b5cb346a7fbe4e04f4b4e3585cd2aab6b71de0f734e3
|
|
4
|
+
data.tar.gz: 5054b253d6f7e944ffdfd09575b3401f2bd6371a5ea90190c9ba8dcfd16a3e58
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d117e27f37ed366fe1fde852da5d7083d757e917d4badf9e1af4419885d4ea8a906571518572ca39842b6f34347dd010ea8e2e735cc63dcf194c3988246ff05a
|
|
7
|
+
data.tar.gz: 9e87de47b40b4ae05197ad764f5e8f0c9d941798dfff736553d579d1eba06f5552de354e5b21cd5cc4446897646168eb1fd846f7c8ae5f02646fe192970f021f
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
class Iro::Api::StocksController < Iro::ApiController
|
|
3
|
-
before_action :set_stock, only: [:
|
|
3
|
+
before_action :set_stock, only: [:destroy, :edit, :max_pain, :show, :update ]
|
|
4
4
|
|
|
5
5
|
def index
|
|
6
6
|
@stocks = Iro::Stock.active
|
|
@@ -12,6 +12,21 @@ class Iro::Api::StocksController < Iro::ApiController
|
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
def max_pain
|
|
16
|
+
authorize! :max_pain, @stock
|
|
17
|
+
|
|
18
|
+
hash = Tda::Option.get_chains({ ticker: @stock.ticker })
|
|
19
|
+
# hash = JSON.parse File.read './trash.json'
|
|
20
|
+
@max_pain = Iro::Option.max_pain hash
|
|
21
|
+
|
|
22
|
+
respond_to do |format|
|
|
23
|
+
format.html
|
|
24
|
+
format.json do
|
|
25
|
+
render layout: false
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
15
30
|
def show
|
|
16
31
|
authorize! :show, @stock
|
|
17
32
|
end_on = Time.now.to_date.in_time_zone('UTC')
|
|
@@ -49,4 +49,14 @@ class Iro::ApiController < ActionController::Base
|
|
|
49
49
|
sign_in user
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
def set_stock
|
|
53
|
+
begin
|
|
54
|
+
@stock = Iro::Stock.find(params[:id])
|
|
55
|
+
rescue Mongoid::Errors::DocumentNotFound => e
|
|
56
|
+
@stock = Iro::Stock.find_by ticker: params[:id]
|
|
57
|
+
end
|
|
58
|
+
@stocks_list = Iro::Stock.tickers_list
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
|
|
52
62
|
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## https://www.macrotrends.net/stocks/charts/META/meta-platforms/stock-price-history
|
|
4
4
|
##
|
|
5
5
|
class Iro::StocksController < Iro::ApplicationController
|
|
6
|
-
before_action :set_stock, only: [:
|
|
6
|
+
before_action :set_stock, only: [:destroy, :edit, :show, :update ]
|
|
7
7
|
|
|
8
8
|
def create
|
|
9
9
|
@stock = Iro::Stock.new(stock_params)
|
|
@@ -38,6 +38,8 @@ class Iro::StocksController < Iro::ApplicationController
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
|
|
42
|
+
|
|
41
43
|
def new
|
|
42
44
|
@stock = Iro::Stock.new
|
|
43
45
|
authorize! :new, @stock
|
|
@@ -64,6 +66,25 @@ class Iro::StocksController < Iro::ApplicationController
|
|
|
64
66
|
symbol: @stock.ticker,
|
|
65
67
|
}).order_by({ date: :desc }).limit(100)
|
|
66
68
|
|
|
69
|
+
filename = "./data/schwab/#{Time.now.to_date.to_s}-#{@stock.ticker}-chains.json"
|
|
70
|
+
if File.exists? filename
|
|
71
|
+
hash = JSON.parse File.read filename
|
|
72
|
+
else
|
|
73
|
+
hash = Tda::Option.get_chains({ ticker: @stock.ticker })
|
|
74
|
+
File.write filename, hash.to_json
|
|
75
|
+
end
|
|
76
|
+
@max_pain = Iro::Option.max_pain hash
|
|
77
|
+
@max_pain_summary = {}
|
|
78
|
+
@max_pain.each do |date, types|
|
|
79
|
+
all = types['all']
|
|
80
|
+
@max_pain_summary[date] = all.keys[0]
|
|
81
|
+
all.each do |strike, amount|
|
|
82
|
+
if amount < all[@max_pain_summary[date]]
|
|
83
|
+
@max_pain_summary[date] = strike
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
67
88
|
respond_to do |format|
|
|
68
89
|
format.html
|
|
69
90
|
format.json do
|
data/app/models/iro/option.rb
CHANGED
|
@@ -73,6 +73,7 @@ class Iro::Option
|
|
|
73
73
|
self[:symbol]
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
+
before_save :sync, if: ->() { !Rails.env.test? } ## do not sync in test
|
|
76
77
|
def sync
|
|
77
78
|
out = Tda::Option.get_quote({
|
|
78
79
|
contractType: put_call,
|
|
@@ -86,6 +87,53 @@ class Iro::Option
|
|
|
86
87
|
# self.save
|
|
87
88
|
end
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
def self.max_pain hash
|
|
91
|
+
outs = {}
|
|
92
|
+
|
|
93
|
+
%w| put call |.each do |contractType|
|
|
94
|
+
dates = hash["#{contractType}ExpDateMap"]
|
|
95
|
+
dates.each do |_date, strikes| ## _date="2023-02-10:5"
|
|
96
|
+
date = _date.split(':')[0].to_date.to_s
|
|
97
|
+
outs[date] ||= {
|
|
98
|
+
'all' => {},
|
|
99
|
+
'put' => {},
|
|
100
|
+
'call' => {},
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
strikes.each do |_strike, _v| ## _strike="18.5"
|
|
104
|
+
strike = _strike.to_f
|
|
105
|
+
|
|
106
|
+
## calls
|
|
107
|
+
mem_c = 0
|
|
108
|
+
strikes.keys.reverse.each do |_key|
|
|
109
|
+
if _key == _strike
|
|
110
|
+
break
|
|
111
|
+
end
|
|
112
|
+
key = _key.to_f
|
|
113
|
+
tmp = hash["callExpDateMap"][_date][_key][0]['openInterest'] * ( key - strike )
|
|
114
|
+
mem_c += tmp
|
|
115
|
+
end
|
|
116
|
+
outs[date]['call'][_strike] = mem_c
|
|
117
|
+
|
|
118
|
+
## puts
|
|
119
|
+
mem_p = 0
|
|
120
|
+
strikes.keys.each do |_key|
|
|
121
|
+
if _key == _strike
|
|
122
|
+
break
|
|
123
|
+
end
|
|
124
|
+
key = _key.to_f
|
|
125
|
+
tmp = hash["putExpDateMap"][_date][_key][0]['openInterest'] * ( strike - key )
|
|
126
|
+
mem_p += tmp
|
|
127
|
+
end
|
|
128
|
+
outs[date]['put'][_strike] = mem_p
|
|
129
|
+
outs[date]['all'][_strike] = mem_c + mem_p
|
|
130
|
+
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
return outs
|
|
136
|
+
end
|
|
137
|
+
|
|
90
138
|
|
|
91
139
|
end
|
data/app/models/iro/priceitem.rb
CHANGED
|
@@ -11,6 +11,7 @@ class Iro::Priceitem
|
|
|
11
11
|
## PUT, CALL, STOCK
|
|
12
12
|
field :putCall, type: String ## kind
|
|
13
13
|
field :symbol, type: String
|
|
14
|
+
field :description, type: String
|
|
14
15
|
field :ticker, type: String
|
|
15
16
|
# belongs_to :stock, inverse_of: :priceitems
|
|
16
17
|
|
|
@@ -33,7 +34,12 @@ class Iro::Priceitem
|
|
|
33
34
|
field :exchangeName, type: String
|
|
34
35
|
field :volatility, type: Float
|
|
35
36
|
|
|
36
|
-
field :
|
|
37
|
+
field :expirationDate, type: :date
|
|
38
|
+
field :delta, type: Float
|
|
39
|
+
field :gamma, type: Float
|
|
40
|
+
field :theta, type: Float
|
|
41
|
+
field :openInterest, type: Integer
|
|
42
|
+
field :strikePrice, type: Float
|
|
37
43
|
|
|
38
44
|
def self.my_find props={}
|
|
39
45
|
lookup = { '$lookup': {
|
data/app/models/tda/option.rb
CHANGED
|
@@ -35,23 +35,32 @@ class Tda::Option
|
|
|
35
35
|
}
|
|
36
36
|
path = "/chains"
|
|
37
37
|
out = self.get path, {
|
|
38
|
-
basic_auth: { username: SCHWAB_DATA[:key], password: SCHWAB_DATA[:secret] },
|
|
39
38
|
headers: headers,
|
|
40
39
|
query: query }
|
|
41
40
|
timestamp = DateTime.parse out.headers['date']
|
|
42
|
-
out = out.parsed_response
|
|
41
|
+
out = out.parsed_response
|
|
43
42
|
|
|
44
|
-
byebug
|
|
43
|
+
# byebug
|
|
45
44
|
|
|
46
45
|
outs = []
|
|
47
46
|
%w| put call |.each do |contractType|
|
|
48
|
-
|
|
49
|
-
_out = out[tmp_sym]
|
|
47
|
+
_out = out["#{contractType}ExpDateMap"]
|
|
50
48
|
_out.each do |date, vs| ## date="2023-02-10:5"
|
|
51
49
|
vs.each do |strike, _v| ## strike="18.5"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
_v = _v[0] ## weird, keep
|
|
51
|
+
# puts! _v, '_v'
|
|
52
|
+
|
|
53
|
+
v = {
|
|
54
|
+
putCall: _v['putCall'],
|
|
55
|
+
symbol: _v['symbol'],
|
|
56
|
+
bid: _v['bid'],
|
|
57
|
+
ask: _v['ask'],
|
|
58
|
+
last: _v['last'],
|
|
59
|
+
totalVolume: _v['totalVolume'],
|
|
60
|
+
openInterest: _v['openInterest'],
|
|
61
|
+
strikePrice: _v['strikePrice'],
|
|
62
|
+
expirationDate: _v['expirationDate'],
|
|
63
|
+
}
|
|
55
64
|
v.each do |k, i|
|
|
56
65
|
if i == 'NaN'
|
|
57
66
|
v[k] = nil
|
|
@@ -66,11 +75,13 @@ class Tda::Option
|
|
|
66
75
|
end
|
|
67
76
|
|
|
68
77
|
outs.each do |out|
|
|
69
|
-
opi = ::Iro::
|
|
78
|
+
opi = ::Iro::Priceitem.create( out )
|
|
70
79
|
if !opi.persisted?
|
|
71
|
-
puts! opi.errors.full_messages, "Cannot create
|
|
80
|
+
puts! opi.errors.full_messages, "Cannot create PriceItem"
|
|
72
81
|
end
|
|
73
82
|
end
|
|
83
|
+
|
|
84
|
+
return out
|
|
74
85
|
end
|
|
75
86
|
|
|
76
87
|
##
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
json.ticker @stock.ticker
|
|
3
|
+
json.last @stock.last
|
|
4
|
+
|
|
5
|
+
json.max_pain do
|
|
6
|
+
@max_pain.each do |date, maps|
|
|
7
|
+
json.set! date do
|
|
8
|
+
json.all do
|
|
9
|
+
json.array! maps['all'] do |strike, value|
|
|
10
|
+
json.strike strike
|
|
11
|
+
json.value value
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
|
data/config/routes.rb
CHANGED
|
@@ -35,13 +35,14 @@ Iro::Engine.routes.draw do
|
|
|
35
35
|
|
|
36
36
|
get 'api/oauth2-redirect.html', to: 'api#oauth2_redirect'
|
|
37
37
|
namespace :api do
|
|
38
|
-
get 'stocks',
|
|
39
|
-
get 'stocks/:ticker',
|
|
40
|
-
get 'stocks/:ticker/
|
|
41
|
-
get 'stocks/:ticker/from/:begin_on', to: 'stocks#show'
|
|
42
|
-
get 'stocks/:ticker/begin_on/:begin_on', to: 'stocks#show'
|
|
43
|
-
get 'stocks/:ticker/from/:begin_on/to/:end_on', to: 'stocks#show'
|
|
38
|
+
get 'stocks', to: 'stocks#index'
|
|
39
|
+
get 'stocks/:ticker', to: 'stocks#show'
|
|
40
|
+
get 'stocks/:ticker/begin_on/:begin_on', to: 'stocks#show'
|
|
44
41
|
get 'stocks/:ticker/begin_on/:begin_on/end_on/:end_on', to: 'stocks#show'
|
|
42
|
+
get 'stocks/:ticker/from/:begin_on', to: 'stocks#show'
|
|
43
|
+
get 'stocks/:ticker/from/:begin_on/to/:end_on', to: 'stocks#show'
|
|
44
|
+
get 'stocks/:ticker/max-pain', to: 'stocks#max_pain'
|
|
45
|
+
get 'stocks/:ticker/period/:period', to: 'stocks#show'
|
|
45
46
|
end
|
|
46
47
|
|
|
47
48
|
end
|
data/lib/tasks/test_tasks.rake
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
|
|
2
2
|
namespace :test do
|
|
3
3
|
|
|
4
|
+
desc 'max pain'
|
|
5
|
+
task max_pain: :environment do
|
|
6
|
+
hash = JSON.parse File.read './trash.json'
|
|
7
|
+
puts! hash.keys, '+++ +++ parsed hash'
|
|
8
|
+
outs = Iro::Option.max_pain hash
|
|
9
|
+
byebug
|
|
10
|
+
end
|
|
11
|
+
|
|
4
12
|
desc 'stock#volatility_mo'
|
|
5
13
|
task stock_vol_mo: :environment do
|
|
6
14
|
out = Iro::Stock.find_by( ticker: 'NVDA' ).volatility_from_mo
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: iron_warbler
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.7.
|
|
4
|
+
version: 2.0.7.40
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Victor Pudeyev
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-08-
|
|
11
|
+
date: 2024-08-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: business_time
|
|
@@ -260,6 +260,7 @@ files:
|
|
|
260
260
|
- app/views/iro/alerts/_form.haml
|
|
261
261
|
- app/views/iro/alerts/index.haml
|
|
262
262
|
- app/views/iro/api/stocks/index.json.jbuilder
|
|
263
|
+
- app/views/iro/api/stocks/max_pain.json.jbuilder
|
|
263
264
|
- app/views/iro/api/stocks/show.json.jbuilder
|
|
264
265
|
- app/views/iro/api/stocks/show.json.jbuilder-bk
|
|
265
266
|
- app/views/iro/application/home.haml
|