ish_models 0.0.33.152 → 0.0.33.157

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: eda424943e1eef920292be882d4c3d0f4de268fb556d4e85b0f099c793a577e2
4
- data.tar.gz: 5c74167f789c8ac201c90a01c3f4c4a16bfd2ea965b2191990ab6c57daae7717
3
+ metadata.gz: 39d1f84c7a5f67986bcdabe0452417ca60d29474b76ce8f5e30996d69ea6381a
4
+ data.tar.gz: 3330d74f59f302da138729b3d50578232fd1dde889ce1615acd641a6c1bb8ff0
5
5
  SHA512:
6
- metadata.gz: 8f98bc72d8dc91b8061b28bfeec8954d283c3e811c6dc7a6e7cb2e574818417232f154c9d5271cf28a25e76f500dc637454c77c9bcb9fe43e86bb8f6a3f789fd
7
- data.tar.gz: 5a6858c1ca87bf1c3d3dc293a01263682f5dede179c1bb07380eb70c7f1a0a4451106419263b1f9c421895a49d2307a7224ad9bed0773629e05c22e24152adab
6
+ metadata.gz: 17049062ec4c11a3937e9e3e39eba3d4f18b97882359a0ac72f9596f034f84c425bda551f36757885af48feb6bbd42603976b00d1bb3707e7a67336121e20b58
7
+ data.tar.gz: 1fc3d98a4ac0cb4dfeedc247cdbeaa809c98d6cddabdf6a6096a05b91c55389573ed715298d60267f242a339d6444276b3d56542b590396d299580708e0ba74f
@@ -37,8 +37,10 @@ class Ish::UserProfile
37
37
  has_many :leads, :class_name => '::Ish::Lead'
38
38
  has_many :photos
39
39
  has_many :reports, inverse_of: :user_profile
40
- has_many :stocks, :class_name => '::Warbler::StockWatch'
41
- has_many :option_watches, class_name: '::Warbler::OptionWatch'
40
+
41
+ # has_many :stock_watches, class_name: 'IronWarbler::StockWatch'
42
+ # has_many :option_watches, class_name: 'IronWarbler::OptionWatch'
43
+
42
44
  has_many :videos, inverse_of: :user_profile
43
45
  has_many :newsitems, inverse_of: :user_profile
44
46
 
data/lib/ish_models.rb CHANGED
@@ -61,15 +61,5 @@ require 'tag'
61
61
  require 'venue'
62
62
  require 'video'
63
63
 
64
- require 'warbler/option_watch'
65
- require 'warbler/stock_watch'
66
- require 'warbler/ameritrade'
67
-
68
- ## warbler
69
- # require 'warbler/covered_call'
70
- # require 'warbler/iron_condor'
71
- # require 'warbler/stock_action'
72
-
73
-
74
64
 
75
65
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ish_models
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.33.152
4
+ version: 0.0.33.157
5
5
  platform: ruby
6
6
  authors:
7
7
  - piousbox
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 7.0.5
19
+ version: 7.3.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 7.0.5
26
+ version: 7.3.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: mongoid_paranoia
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -156,17 +156,6 @@ files:
156
156
  - lib/tag.rb
157
157
  - lib/venue.rb
158
158
  - lib/video.rb
159
- - lib/warbler/alphavantage_stockwatcher.rb
160
- - lib/warbler/ameritrade.rb
161
- - lib/warbler/covered_call.rb
162
- - lib/warbler/covered_call_watcher.rb
163
- - lib/warbler/iron_condor.rb
164
- - lib/warbler/iron_condor_watcher.rb
165
- - lib/warbler/option_watch.rb
166
- - lib/warbler/stock_action.rb
167
- - lib/warbler/stock_option.rb
168
- - lib/warbler/stock_watch.rb
169
- - lib/warbler/yahoo_stockwatcher.rb
170
159
  homepage: https://wasya.co
171
160
  licenses:
172
161
  - Proprietary
@@ -1,42 +0,0 @@
1
-
2
- class AlphavantageStockwatcher
3
-
4
- def initialize
5
- end
6
-
7
- # every minute, for alphavantage.co
8
- def watch
9
- while true
10
-
11
- if Time.now.hour > 14 && Time.now.hours < 21
12
-
13
- stocks = Ish::StockWatch.where( :notification_type => :EMAIL )
14
- # puts! stocks.map(&:ticker), "Watching these stocks:"
15
- stocks.each do |stock|
16
- # puts! stock.ticker, 'stock'
17
- r = HTTParty.get "https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=#{stock.ticker}&interval=1min&apikey=X1C5GGH5MZSXMF3O", timeout: 10
18
- r2 = JSON.parse( r.body )['Time Series (1min)']
19
- r3 = r2[r2.keys.first]['4. close'].to_f
20
- if stock.direction == :ABOVE && r3 >= stock.price ||
21
- stock.direction == :BELOW && r3 <= stock.price
22
- IshManager::ApplicationMailer.stock_alert( stock ).deliver
23
-
24
- ## actions
25
- ## exit the position
26
- # stock.stock_actions.where( :is_active => true ).each do |action|
27
- # # @TODO: actions
28
- # end
29
-
30
- end
31
- end
32
- print '.'
33
- else
34
- print '-'
35
- end
36
-
37
- sleep 60
38
-
39
- end
40
- end
41
-
42
- end
@@ -1,90 +0,0 @@
1
-
2
- require 'httparty'
3
-
4
- #
5
- # * make calls every once in a while
6
- # * If the option price dips below a threshold, close the position (create the order to buy back the option)
7
- #
8
-
9
- # cron job or service? Well, I've historically done service. Cron is easier tho. The wiring should be for both.
10
-
11
- # https://developer.tdameritrade.com/option-chains/apis/get/marketdata/chains
12
- # FVRR_082021P200
13
-
14
-
15
- module Warbler::Ameritrade
16
-
17
- CONFIG = {
18
- underlying_downprice_tolerance: 0.14,
19
- }
20
-
21
- ## AKA stop loss
22
- def self.main_fvrr_2
23
-
24
- # @TODO: pass the info on the position in here.
25
- strike_price = 200
26
-
27
- # What is my risk tolerance here? 14% down movement of the underlying
28
- response = ::Warbler::Ameritrade::Api.get_quote({ symbol: 'FVRR' })
29
- last_price = response[:lastPrice]
30
- tolerable_price = ( strike_price * (1-CONFIG[:underlying_downprice_tolerance]) )
31
-
32
- if last_price < tolerable_price
33
- puts! 'LIMIT TRIGGERED, LETS EXIT' # @TODO: send an email
34
- end
35
- end
36
-
37
- end
38
-
39
- class ::Warbler::Ameritrade::Api
40
- include ::HTTParty
41
- base_uri 'https://api.tdameritrade.com'
42
- PUT = 'PUT'
43
- CALL = 'CALL'
44
-
45
- def self.get_quote opts
46
- # validate input
47
- %i| symbol |.each do |s|
48
- if !opts[s]
49
- raise Ish::InputError.new("invalid input, missing #{s}")
50
- end
51
- end
52
-
53
- path = "/v1/marketdata/#{opts[:symbol]}/quotes"
54
- out = self.get path, { query: { apikey: ::TD_AME[:apiKey] } }
55
- out = out.parsed_response[out.parsed_response.keys[0]].symbolize_keys
56
- out
57
- end
58
-
59
- def self.get_option _opts
60
- opts = {}
61
-
62
- # validate input
63
- validOpts = %i| contractType strike |
64
- validOpts.each do |s|
65
- if _opts[s]
66
- opts[s] = _opts[s]
67
- else
68
- raise Ish::InputError.new("Invalid input, missing '#{s}'.")
69
- end
70
- end
71
- if _opts[:date]
72
- opts[:fromDate] = opts[:toDate] = _opts[:date]
73
- else
74
- raise Ish::InputError.new("Invalid input, missing 'date'.")
75
- end
76
- if _opts[:ticker]
77
- opts[:symbol] = _opts[:ticker].upcase
78
- else
79
- raise Ish::InputError.new("Invalid input, missing 'ticker'.")
80
- end
81
-
82
- query = { apikey: ::TD_AME[:apiKey], strikeCount: 1 }.merge opts
83
- path = "/v1/marketdata/chains"
84
- out = self.get path, { query: query }
85
- out = out.parsed_response.deep_symbolize_keys
86
- tmp_sym = "#{opts[:contractType].to_s.downcase}ExpDateMap".to_sym
87
- out[tmp_sym].first[1].first[1][0]
88
- end
89
-
90
- end
@@ -1,20 +0,0 @@
1
-
2
- class Ish::CoveredCall
3
- include Mongoid::Document
4
- include Mongoid::Timestamps
5
-
6
- store_in collection: 'ish_covered_call'
7
-
8
- field :expires_on, type: Date
9
- validates :expires_on, presence: true
10
- field :n_contracts, type: Integer
11
- validates :n_contracts, presence: true
12
- field :ticker
13
- validates :ticker, uniqueness: { scope: :expires_on }
14
- validates :ticker, presence: true
15
-
16
- #
17
- # Internal, below
18
- #
19
-
20
- end
@@ -1,78 +0,0 @@
1
-
2
- class ::Ish::CoveredCallWatcher
3
-
4
- def initialize
5
- @consumer = OAuth::Consumer.new ALLY_CREDS[:consumer_key], ALLY_CREDS[:consumer_secret], { :site => 'https://api.tradeking.com' }
6
- @access_token = OAuth::AccessToken.new(@consumer, ALLY_CREDS[:access_token], ALLY_CREDS[:access_token_secret])
7
- end
8
-
9
- def new_order
10
- ccall = ::Ish::CoveredCall.all.first
11
- xml = ccall.new_multileg_order_example
12
- print! xml, 'xml'
13
- path = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders.xml"
14
- # path = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders/preview.xml"
15
- response = @access_token.post(path, xml)
16
- print! response.body, 'response'
17
- end
18
-
19
- def watch_once
20
- ccalls = ::Ish::CoveredCall.all
21
- ccalls.each do |ccall|
22
- puts! ccall.ticker, 'Watching this ccall'
23
-
24
- path = "/v1/market/ext/quotes.json?symbols=#{ccall.ticker}"
25
- response = @access_token.get(path, {'Accept' => 'application/json'})
26
- json = JSON.parse( response.body ).deep_symbolize_keys
27
- bid = json[:response][:quotes][:quote][:bid].to_f
28
- ask = json[:response][:quotes][:quote][:ask].to_f
29
- natural = ( bid + ask ) / 2
30
-
31
- # puts! [ bid, ask ], 'bid, ask'
32
- # puts! [ ccall.upper_panic_threshold, ccall.lower_panic_threshold ], 'upper/lower panic'
33
-
34
- ## upper panic
35
- if bid > ccall.upper_panic_threshold
36
- xml = ccall.rollup_xml access_token=@access_token, natural=natural
37
- print! xml, 'xml'
38
-
39
- IshManager::ApplicationMailer.ccall_followup_alert( ccall, { action: :rollup } ).deliver_later
40
-
41
- ## place order
42
- path_preview = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders/preview.xml"
43
- response = @access_token.post( path_preview, xml )
44
- print! response.body
45
- # path_order = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders.xml"
46
- # response = @access_token.post( path_order, xml )
47
- # print! response.body
48
- end
49
-
50
- ## lower panic
51
- if ask < ccall.lower_panic_threshold
52
- xml = ccall.rolldown_xml access_token=@access_token, natural=natural
53
- print! xml, 'xml'
54
-
55
- IshManager::ApplicationMailer.ccall_followup_alert( ccall, { action: :rolldown } ).deliver_later
56
-
57
- ## place order
58
- path_preview = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders/preview.xml"
59
- response = @access_token.post( path_preview, xml )
60
- print! response.body
61
- # path_order = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders.xml"
62
- # response = @access_token.post( path_order, xml )
63
- # print! response.body
64
- end
65
-
66
- end
67
- end
68
-
69
- end
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
@@ -1,325 +0,0 @@
1
-
2
- =begin
3
-
4
- c.update_attributes( call_sell_strike: 242, call_buy_strike: 243, put_sell_strike: 229, put_buy_strike: 228 )
5
-
6
- =end
7
-
8
- class Ish::IronCondor
9
- include Mongoid::Document
10
- include Mongoid::Timestamps
11
-
12
- store_in collection: 'ish_iron_condor'
13
-
14
- field :expires_on, type: Date
15
- validates :expires_on, presence: true
16
- field :n_contracts, type: Integer
17
- validates :n_contracts, presence: true
18
- field :ticker
19
- validates :ticker, uniqueness: { scope: :expires_on }
20
- validates :ticker, presence: true
21
-
22
- #
23
- # Internal, below
24
- #
25
-
26
- def created_on; created_at.to_date; end
27
-
28
- def self.all_filled
29
- where( status: :filled )
30
- end
31
-
32
- STATUSES = [ :queued, :placed, :filled, :rolling_up, :rolling_down, :rolled_up, :rolled_down, :expired ]
33
- field :status
34
- field :enter_price, type: Float
35
- field :call_sell_strike, type: Float
36
- field :call_buy_strike, type: Float
37
- field :put_sell_strike, type: Float
38
- field :put_buy_strike, type: Float
39
- field :new_call_sell_strike, type: Float
40
- field :new_call_buy_strike, type: Float
41
- field :new_put_sell_strike, type: Float
42
- field :new_put_buy_strike, type: Float
43
-
44
- field :iv_annual, type: Float
45
- def iv_period
46
- n_days = created_on.business_days_until expires_on
47
- result = iv_annual.to_f / Math.sqrt(252/n_days)
48
- end
49
- alias_method :period_iv, :iv_period
50
-
51
- ## how close to a sell leg I need to be to take followup action
52
- def panic_percentage
53
- 0.01 # 1% for QQQ
54
- end
55
-
56
- def buysell_spread
57
- 1 # $1 for QQQ
58
- end
59
-
60
- def get_call_sell_strike
61
- result = enter_price * ( 1 - period_iv/100 )
62
- result = result.ceil
63
- end
64
- def get_call_buy_strike
65
- call_sell_strike + buysell_spread
66
- end
67
-
68
- def get_put_sell_strike
69
- result = enter_price * ( 1 - period_iv/100 )
70
- result = result.floor
71
- end
72
- def get_put_buy_strike
73
- put_sell_strike - buysell_spread
74
- end
75
-
76
- def upper_panic_threshold
77
- result = call_sell_strike * ( 1 - panic_percentage )
78
- end
79
-
80
- def lower_panic_threshold
81
- result = put_sell_strike * ( 1 + panic_percentage )
82
- end
83
-
84
- def new_multileg_order_example_done
85
- ticker = 'QQQ'
86
- px = 0.08
87
- account_id = ALLY_CREDS[:account_id]
88
- n_contracts = 1
89
- sell_strike = 237.0
90
- buy_strike = 237.5
91
- expiration = '2020-02-21'.to_date
92
-
93
- tmpl = <<~AOL
94
- <FIXML xmlns="http://www.fixprotocol.org/FIXML-5-0-SP2">
95
- <NewOrdMleg TmInForce="0" Px="#{px}" OrdTyp="2" Acct="#{account_id}">
96
- <Ord OrdQty="#{n_contracts}" PosEfct="O">
97
- <Leg Side="2" Strk="#{sell_strike}"
98
- Mat="#{expiration.strftime('%Y-%m-%d')}T00:00:00.000-05:00" MMY="#{expiration.strftime('%y%m')}"
99
- SecTyp="OPT" CFI="OC" Sym="#{ticker}"/>
100
- </Ord>
101
- <Ord OrdQty="#{n_contracts}" PosEfct="O">
102
- <Leg Side="1" Strk="#{buy_strike}"
103
- Mat="#{expiration.strftime('%Y-%m-%d')}T00:00:00.000-05:00" MMY="#{expiration.strftime('%y%m')}"
104
- SecTyp="OPT" CFI="OC" Sym="#{ticker}"/>
105
- </Ord>
106
- </NewOrdMleg>
107
- </FIXML>
108
- AOL
109
- end
110
-
111
- def new_purchase_trash
112
- ticker = 'AXU'
113
- px = 2.06
114
- account_id = ALLY_CREDS[:account_id]
115
- n_contracts = 1
116
- strike = 2.06
117
-
118
- xml = <<~AOL
119
- <FIXML xmlns="http://www.fixprotocol.org/FIXML-5-0-SP2">
120
- <Order TmInForce="0" Typ="1" Side="1" Acct="#{account_id}">
121
- <Instrmt SecTyp="CS" Sym="#{ticker}"/>
122
- <OrdQty Qty="1"/>
123
- </Order>
124
- </FIXML>
125
- AOL
126
- end
127
-
128
- ## https://www.ally.com/api/invest/documentation/fixml/
129
- ## https://www.ally.com/api/invest/documentation/trading/
130
- ## follow up, roll up
131
- ## buy call to close
132
- ## sell call to close
133
- ## sell call to open
134
- ## buy call to open
135
- def rollup_xml access_token=nil, natural=nil
136
- @access_token ||= access_token
137
-
138
- new_call_sell_strike = ( natural * ( 1 + period_iv ) ).ceil
139
- new_call_buy_strike = new_call_sell_strike + buysell_spread
140
-
141
- # get the costs of the option first, to compute `Px`
142
- ymd = expires_on.strftime('%y%m%d')
143
- price8 = (new_call_sell_strike*1000).to_i.to_s.rjust(8, '0')
144
- path = "/v1/market/ext/quotes.json?symbols=#{ticker}#{ymd}C#{price8}"
145
- puts! path, 'path sell'
146
- response = @access_token.post(path, {'Accept' => 'application/json'})
147
- json_sell = JSON.parse( response.body ).deep_symbolize_keys
148
- json_sell_bid = json_sell[:response][:quotes][:quote][:bid].to_f
149
- json_sell_ask = json_sell[:response][:quotes][:quote][:ask].to_f
150
-
151
- price8 = (new_call_buy_strike*1000).to_s.rjust(8, '0')
152
- path = "/v1/market/ext/quotes.json?symbols=#{ticker}#{ymd}C#{price8}"
153
- response = @access_token.post(path, {'Accept' => 'application/json'})
154
- json_buy = JSON.parse( response.body ).deep_symbolize_keys
155
- json_buy_bid = json_buy[:response][:quotes][:quote][:bid].to_f
156
- json_buy_ask = json_buy[:response][:quotes][:quote][:ask].to_f
157
-
158
- px_sell = ( json_sell_bid.to_f + json_sell_ask ) / 2
159
- px_sell = px_sell # .round 2
160
- px_buy = ( json_buy_bid + json_buy_ask )/ 2
161
- px_buy = px_buy # .round 2
162
- px = px_sell - px_buy
163
- px = ( px * 20 ).round.to_f / 20 # down to nearest 0.05
164
-
165
- json_puts! json_sell, 'json_sell'
166
- json_puts! json_buy, 'json_buy'
167
- puts! px, '^00 - px'
168
-
169
- =begin
170
- update( status: :rolling_up,
171
- new_call_sell_strike: new_call_sell_strike,
172
- new_call_buy_strike: new_call_buy_strike )
173
- =end
174
-
175
- rollup_tmpl =<<~AOL
176
- <?xml version="1.0" encoding="UTF-8"?>
177
- <FIXML xmlns="http://www.fixprotocol.org/FIXML-5-0-SP2">
178
- <NewOrdMleg
179
- OrdTyp="2"
180
- Px="#{px}"
181
- Acct="#{ALLY_CREDS[:account_id]}"
182
- TmInForce="0"
183
- >
184
- <Ord OrdQty="#{n_contracts}" PosEfct="C" >
185
- <Leg
186
- AcctTyp="5"
187
- Side="1"
188
- Strk="#{call_sell_strike}"
189
- Mat="#{expires_on.strftime('%Y-%m-%d')}T00:00:00.000‐05:00"
190
- MMY="#{expires_on.strftime('%Y%m')}"
191
- SecTyp="OPT"
192
- CFI="OC"
193
- Sym="#{ticker}" />
194
- </Ord>
195
- <Ord OrdQty="#{n_contracts}" PosEfct="C" >
196
- <Leg
197
- Side="2"
198
- Strk="#{call_buy_strike}"
199
- Mat="#{expires_on.strftime('%Y-%m-%d')}T00:00:00.000‐05:00"
200
- MMY="#{expires_on.strftime('%Y%m')}"
201
- SecTyp="OPT"
202
- CFI="OC"
203
- Sym="#{ticker}" />
204
- </Ord>
205
- <Ord OrdQty="#{n_contracts}" PosEfct="O" >
206
- <Leg
207
- Side="2"
208
- Strk="#{new_call_sell_strike}"
209
- Mat="#{expires_on.strftime('%Y-%m-%d')}T00:00:00.000‐05:00"
210
- MMY="#{expires_on.strftime('%Y%m')}"
211
- SecTyp="OPT"
212
- CFI="OC"
213
- Sym="#{ticker}" />
214
- </Ord>
215
- <Ord OrdQty="#{n_contracts}" PosEfct="O" >
216
- <Leg
217
- Side="1"
218
- Strk="#{new_call_buy_strike}"
219
- Mat="#{expires_on.strftime('%Y-%m-%d')}T00:00:00.000‐05:00"
220
- MMY="#{expires_on.strftime('%Y%m')}"
221
- SecTyp="OPT"
222
- CFI="OC"
223
- Sym="#{ticker}" />
224
- </Ord>
225
- </NewOrdMleg>
226
- </FIXML>
227
- AOL
228
- end
229
-
230
- def rolldown_xml access_token=nil, natural=nil
231
- @access_token ||= access_token
232
-
233
- new_put_sell_strike = ( natural * ( 1 - period_iv ) ).floor
234
- new_put_buy_strike = new_put_sell_strike - buysell_spread
235
-
236
- # get the costs of the option first, to compute `Px`
237
- ymd = expires_on.strftime('%y%m%d')
238
- price8 = (new_put_sell_strike*1000).to_i.to_s.rjust(8, '0')
239
- path = "/v1/market/ext/quotes.json?symbols=#{ticker}#{ymd}C#{price8}"
240
- puts! path, 'path sell'
241
- response = @access_token.post(path, {'Accept' => 'application/json'})
242
- json_sell = JSON.parse( response.body ).deep_symbolize_keys
243
- json_sell_bid = json_sell[:response][:quotes][:quote][:bid].to_f
244
- json_sell_ask = json_sell[:response][:quotes][:quote][:ask].to_f
245
- json_puts! json_sell, 'json_sell'
246
-
247
- price8 = (new_put_buy_strike*1000).to_s.rjust(8, '0')
248
- path = "/v1/market/ext/quotes.json?symbols=#{ticker}#{ymd}C#{price8}"
249
- puts! path, 'path buy'
250
- response = @access_token.post(path, {'Accept' => 'application/json'})
251
- json_buy = JSON.parse( response.body ).deep_symbolize_keys
252
- json_buy_bid = json_buy[:response][:quotes][:quote][:bid].to_f
253
- json_buy_ask = json_buy[:response][:quotes][:quote][:ask].to_f
254
- json_puts! json_buy, 'json_buy'
255
-
256
- px_sell = ( json_sell_bid.to_f + json_sell_ask ) / 2
257
- px_sell = px_sell # .round 2
258
- px_buy = ( json_buy_bid + json_buy_ask )/ 2
259
- px_buy = px_buy # .round 2
260
- px = px_sell - px_buy
261
- px = ( px * 20 ).round.to_f / 20 # down to nearest 0.05
262
- puts! px, 'px'
263
-
264
- =begin
265
- update( status: :rolling_down,
266
- new_put_sell_strike: new_put_sell_strike,
267
- new_put_buy_strike: new_put_buy_strike )
268
- =end
269
-
270
- rollup_tmpl =<<~AOL
271
- <?xml version="1.0" encoding="UTF-8"?>
272
- <FIXML xmlns="http://www.fixprotocol.org/FIXML-5-0-SP2">
273
- <NewOrdMleg
274
- OrdTyp="2"
275
- Px="#{px}"
276
- Acct="#{ALLY_CREDS[:account_id]}"
277
- TmInForce="0"
278
- >
279
- <Ord OrdQty="#{n_contracts}" PosEfct="C" >
280
- <Leg
281
- AcctTyp="5"
282
- Side="1"
283
- Strk="#{put_sell_strike}"
284
- Mat="#{expires_on.strftime('%Y-%m-%d')}T00:00:00.000‐05:00"
285
- MMY="#{expires_on.strftime('%Y%m')}"
286
- SecTyp="OPT"
287
- CFI="OP"
288
- Sym="#{ticker}" />
289
- </Ord>
290
- <Ord OrdQty="#{n_contracts}" PosEfct="C" >
291
- <Leg
292
- Side="2"
293
- Strk="#{put_buy_strike}"
294
- Mat="#{expires_on.strftime('%Y-%m-%d')}T00:00:00.000‐05:00"
295
- MMY="#{expires_on.strftime('%Y%m')}"
296
- SecTyp="OPT"
297
- CFI="OP"
298
- Sym="#{ticker}" />
299
- </Ord>
300
- <Ord OrdQty="#{n_contracts}" PosEfct="O" >
301
- <Leg
302
- Side="2"
303
- Strk="#{new_put_sell_strike}"
304
- Mat="#{expires_on.strftime('%Y-%m-%d')}T00:00:00.000‐05:00"
305
- MMY="#{expires_on.strftime('%Y%m')}"
306
- SecTyp="OPT"
307
- CFI="OP"
308
- Sym="#{ticker}" />
309
- </Ord>
310
- <Ord OrdQty="#{n_contracts}" PosEfct="O" >
311
- <Leg
312
- Side="1"
313
- Strk="#{new_put_buy_strike}"
314
- Mat="#{expires_on.strftime('%Y-%m-%d')}T00:00:00.000‐05:00"
315
- MMY="#{expires_on.strftime('%Y%m')}"
316
- SecTyp="OPT"
317
- CFI="OP"
318
- Sym="#{ticker}" />
319
- </Ord>
320
- </NewOrdMleg>
321
- </FIXML>
322
- AOL
323
- end
324
-
325
- end
@@ -1,95 +0,0 @@
1
-
2
- # result = @access_token.get('/v1/accounts.json', {'Accept' => 'application/json'})
3
- # json = JSON.parse result.body
4
-
5
- class ::Ish::IronCondorWatcher
6
-
7
- def initialize
8
- @consumer = OAuth::Consumer.new ALLY_CREDS[:consumer_key], ALLY_CREDS[:consumer_secret], { :site => 'https://api.tradeking.com' }
9
- @access_token = OAuth::AccessToken.new(@consumer, ALLY_CREDS[:access_token], ALLY_CREDS[:access_token_secret])
10
- end
11
-
12
- def ally_status_update
13
- path = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders.xml"
14
- response = @access_token.get( path, {'Accept' => 'application/json'})
15
- print! response.body, 'body'
16
-
17
- # have model AllyOrder ?
18
- # Then, if the order is filled, adjust the condor (suppose rolled down):
19
- # update field :put_sell_strike
20
- # update field :put_buy_strike
21
- # update field :status => :filled
22
- end
23
-
24
- =begin
25
- def new_order
26
- condor = ::Ish::IronCondor.all.first
27
- xml = condor.new_multileg_order_example
28
- print! xml, 'xml'
29
- path = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders.xml"
30
- # path = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders/preview.xml"
31
- response = @access_token.post(path, xml)
32
- print! response.body, 'response'
33
- end
34
- =end
35
-
36
- def watch_once
37
- condors = ::Ish::IronCondor.all_filled
38
- condors.each do |condor|
39
- puts! condor.ticker, 'Watching this condor'
40
-
41
- path = "/v1/market/ext/quotes.json?symbols=#{condor.ticker}"
42
- response = @access_token.get(path, {'Accept' => 'application/json'})
43
- json = JSON.parse( response.body ).deep_symbolize_keys
44
- bid = json[:response][:quotes][:quote][:bid].to_f
45
- ask = json[:response][:quotes][:quote][:ask].to_f
46
- natural = ( bid + ask ) / 2
47
-
48
- puts! [ bid, ask ], 'bid, ask'
49
- puts! [ condor.upper_panic_threshold, condor.lower_panic_threshold ], 'upper/lower panic'
50
-
51
- ## upper panic
52
- if bid > condor.upper_panic_threshold
53
- xml = condor.rollup_xml access_token=@access_token, natural=natural
54
- print! xml, 'xml'
55
-
56
- IshManager::ApplicationMailer.condor_followup_alert( condor, { action: :rollup } ).deliver_later
57
-
58
- ## place order
59
- path_preview = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders/preview.xml"
60
- response = @access_token.post( path_preview, xml )
61
- print! response.body
62
- # path_order = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders.xml"
63
- # response = @access_token.post( path_order, xml )
64
- # print! response.body
65
- end
66
-
67
- ## lower panic
68
- if ask < condor.lower_panic_threshold
69
- xml = condor.rolldown_xml access_token=@access_token, natural=natural
70
- print! xml, 'xml'
71
-
72
- IshManager::ApplicationMailer.condor_followup_alert( { action: 'rolldown', condor_id: condor.id } ).deliver_later
73
-
74
- ## place order
75
- path_preview = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders/preview.xml"
76
- response = @access_token.post( path_preview, xml )
77
- print! response.body
78
- # path_order = "/v1/accounts/#{ALLY_CREDS[:account_id]}/orders.xml"
79
- # response = @access_token.post( path_order, xml )
80
- # print! response.body
81
- end
82
-
83
- end
84
- end
85
-
86
- end
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
@@ -1,41 +0,0 @@
1
-
2
- class Warbler::OptionWatch
3
- include Mongoid::Document
4
- include Mongoid::Timestamps
5
- store_in collection: 'ish_option_watches'
6
-
7
- SLEEP_TIME_SECONDS = 60
8
-
9
- field :ticker # like NVDA
10
- validates :ticker, presence: true
11
- # field :symbol # like NVDA_021822C230
12
-
13
- ## Strike isn't the same as price!
14
- field :strike, :type => Float
15
- validates :strike, presence: true
16
-
17
- ## What is the price of the option at some strike?
18
- field :price, type: Float
19
- validates :price, presence: true
20
-
21
- field :contractType
22
- validates :contractType, presence: true
23
-
24
- field :date
25
- validates :date, presence: true
26
-
27
- NOTIFICATION_TYPES = [ :NONE, :EMAIL, :SMS ]
28
- ACTIONS = NOTIFICATION_TYPES
29
- NOTIFICATION_NONE = :NONE
30
- NOTIFICATION_EMAIL = :EMAIL
31
- NOTIFICATION_SMS = :SMS
32
- field :notification_type, :type => Symbol, :as => :action
33
-
34
- DIRECTIONS = [ :ABOVE, :BELOW ]
35
- DIRECTION_ABOVE = :ABOVE
36
- DIRECTION_BELOW = :BELOW
37
- field :direction, :type => Symbol
38
-
39
- belongs_to :profile, :class_name => 'Ish::UserProfile'
40
-
41
- end
@@ -1,18 +0,0 @@
1
-
2
- #
3
- # Stock action. Used to act on the existing inventory (before acting to aquire inventory)
4
- # _vp_ 20171026
5
- #
6
- class Ish::StockAction
7
- include Mongoid::Document
8
- include Mongoid::Timestamps
9
-
10
- store_in :collection => 'ish_stock_action'
11
-
12
- belongs_to :profile, :class_name => 'Ish::UserProfile'
13
- belongs_to :stock_watch, :class_name => 'Ish::StockWatch'
14
- has_many :stock_options, :class_name => 'Ish::StockOption'
15
-
16
- field :is_active, :type => Boolean, :default => true # whether anything will be done upon alert trigger
17
-
18
- end
@@ -1,29 +0,0 @@
1
-
2
- #
3
- # Stock Option. Owned by a person. This is a position that is held (or historical data).
4
- # _vp_ 20171026
5
- #
6
- class Ish::StockOption
7
- include Mongoid::Document
8
- include Mongoid::Timestamps
9
-
10
- store_in :collection => 'ish_stock_option'
11
-
12
- field :ticker
13
- field :expires_on, :type => Date
14
- field :strike, :type => Float
15
-
16
- DIRECTIONS = [ :CALL, :PUT ]
17
- field :direction, :type => Symbol
18
-
19
- field :quantity, :type => Integer
20
- field :is_active, :type => Integer, :default => true # whether this position is current or in the past
21
-
22
- belongs_to :profile, :class_name => 'Ish::UserProfile'
23
- belongs_to :stock_action, :class_name => 'Ish::StockAction', :optional => true
24
-
25
- def to_s
26
- "#{self.ticker} #{self.expires_on.to_time.strftime('%b %d %Y')} #{self.strike} (x #{self.quantity})"
27
- end
28
-
29
- end
@@ -1,27 +0,0 @@
1
-
2
- class Warbler::StockWatch
3
- include Mongoid::Document
4
- include Mongoid::Timestamps
5
- store_in collection: 'ish_stock_watches'
6
-
7
- SLEEP_TIME_SECONDS = 60
8
-
9
- field :ticker
10
-
11
- NOTIFICATION_TYPES = [ :NONE, :EMAIL, :SMS ]
12
- ACTIONS = NOTIFICATION_TYPES
13
- NOTIFICATION_NONE = :NONE
14
- NOTIFICATION_EMAIL = :EMAIL
15
- NOTIFICATION_SMS = :SMS
16
- field :notification_type, :type => Symbol, :as => :action
17
-
18
- field :price, :type => Float
19
-
20
- DIRECTIONS = [ :ABOVE, :BELOW ]
21
- DIRECTION_ABOVE = :ABOVE
22
- DIRECTION_BELOW = :BELOW
23
- field :direction, :type => Symbol
24
-
25
- belongs_to :profile, :class_name => 'Ish::UserProfile'
26
-
27
- end
@@ -1,29 +0,0 @@
1
-
2
- class ::YahooStockwatcher
3
-
4
- # For: https://query1.finance.yahoo.com/v7/finance/chart/qqq?interval=1d&indicators=quote
5
- def watch_once
6
-
7
- stocks = Ish::StockWatch.where( :notification_type => :EMAIL )
8
- # puts! stocks.map(&:ticker), "Watching these stocks"
9
- stocks.each do |stock|
10
- # puts! stock.ticker, 'ticker'
11
- r = HTTParty.get "https://query1.finance.yahoo.com/v7/finance/chart/#{stock.ticker}?interval=1d&indicators=quote", timeout: 10
12
- r = JSON.parse( r.body ).deep_symbolize_keys
13
- r = r[:chart][:result][0][:meta][:regularMarketPrice]
14
- if stock.direction == :ABOVE && r >= stock.price ||
15
- stock.direction == :BELOW && r <= stock.price
16
- IshManager::ApplicationMailer.stock_alert( stock ).deliver
17
-
18
- ## actions
19
- ## exit the position
20
- # stock.stock_actions.where( :is_active => true ).each do |action|
21
- # # @TODO: actions
22
- # end
23
-
24
- end
25
- end
26
-
27
- end
28
-
29
- end