ish_models 0.0.33.152 → 0.0.33.157

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: 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