wco_models 3.1.0.268 → 3.1.0.270
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/models/iro/option.rb +1 -1
- data/app/models/iro/position.rb +64 -22
- data/app/models/iro/purse.rb +1 -1
- data/app/models/iro/strategy.rb +12 -4
- data/app/models/tda/option.rb +8 -8
- data/app/models/tda/order.rb +4 -4
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 021150c40e30bb02fb18567bf718130b52075e9fa8bcb999e231f95c80413ed9
|
|
4
|
+
data.tar.gz: 52f7e91b77c3ead85ced22ccd64f4267cfc96d3fddf59671fa115ce413c13267
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dbfe2e00671a9ca7dc6c232186993e45f00c7afd6e74f4f2140d0902c19e29c5e709462dfef1d41112a2f9652e04c6b367fc5b878ce32ffc8d07d11245aafc07
|
|
7
|
+
data.tar.gz: 2160353727634f5e7df835689ab93192d6e95dc42f37d600ef346a840d1221d5812c9c790d0e480dbf0312dfd8c6d3bb83b033bf66ca1877143eb3b3b4b59b50
|
data/app/models/iro/option.rb
CHANGED
|
@@ -102,7 +102,7 @@ class Iro::Option
|
|
|
102
102
|
expirationDate: expires_on.strftime('%Y-%m-%d'),
|
|
103
103
|
ticker: ticker,
|
|
104
104
|
})
|
|
105
|
-
puts! out, "option sync of `#{self.to_s}`"
|
|
105
|
+
# puts! out, "option sync of `#{self.to_s}`"
|
|
106
106
|
self.end_price = ( out.bid + out.ask ) / 2 rescue 0
|
|
107
107
|
self.end_delta = out.delta ? out.delta : 0.0
|
|
108
108
|
self.save! ## 2026-02-19 this must be present.
|
data/app/models/iro/position.rb
CHANGED
|
@@ -142,7 +142,7 @@ class Iro::Position
|
|
|
142
142
|
end
|
|
143
143
|
|
|
144
144
|
|
|
145
|
-
field :pending_price
|
|
145
|
+
field :pending_price, type: :float
|
|
146
146
|
|
|
147
147
|
## credit spread only
|
|
148
148
|
def close_price
|
|
@@ -151,8 +151,8 @@ class Iro::Position
|
|
|
151
151
|
return out.round(2)
|
|
152
152
|
end
|
|
153
153
|
|
|
154
|
-
##
|
|
155
|
-
def
|
|
154
|
+
## credit-spread
|
|
155
|
+
def open_price
|
|
156
156
|
pos = self
|
|
157
157
|
out = pos.inner.begin_price - pos.outer.begin_price
|
|
158
158
|
return out.round(2)
|
|
@@ -208,6 +208,50 @@ class Iro::Position
|
|
|
208
208
|
outer.sync
|
|
209
209
|
end
|
|
210
210
|
|
|
211
|
+
def schwab_query
|
|
212
|
+
pos = self
|
|
213
|
+
case pos.intent
|
|
214
|
+
when Iro::Strategy::INTENT_OPEN
|
|
215
|
+
the_q = Tda::Order.credit_spread_q pos
|
|
216
|
+
when Iro::Strategy::INTENT_ROLL
|
|
217
|
+
the_q = Tda::Order.roll_credit_call_spread_q pos
|
|
218
|
+
else
|
|
219
|
+
throw "prp - #schwab_query undefined for position #{pos.inspect}"
|
|
220
|
+
end
|
|
221
|
+
return the_q
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def self.sync_all
|
|
225
|
+
@positions = Iro::Position.where( :status.in => [ 'active', 'pending' ] )
|
|
226
|
+
expiration_dates = @positions.map { |p| p.expires_on.to_s }.sort
|
|
227
|
+
# puts! expiration_dates, 'expiration_dates'
|
|
228
|
+
|
|
229
|
+
count = 1
|
|
230
|
+
@positions.each do |pos|
|
|
231
|
+
# puts! pos.to_s, 'pos TMP'
|
|
232
|
+
|
|
233
|
+
quotes_h = Tda::Option.get_quotes_h({
|
|
234
|
+
contractType: 'ALL',
|
|
235
|
+
ticker: pos.ticker,
|
|
236
|
+
fromDate: expiration_dates.first,
|
|
237
|
+
toDate: expiration_dates.last,
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
pos.inner.end_price = quotes_h[pos.expires_on.to_s][pos.put_call][pos.inner.strike][:price]
|
|
241
|
+
pos.inner.end_delta = quotes_h[pos.expires_on.to_s][pos.put_call][pos.inner.strike][:delta]
|
|
242
|
+
pos.inner.save ? print("#{count}^") : print("#{count}X")
|
|
243
|
+
if [ Iro::Strategy::KIND_LONG_CREDIT_PUT_SPREAD, Iro::Strategy::KIND_SHORT_CREDIT_CALL_SPREAD ].include?( pos.strategy.kind )
|
|
244
|
+
pos.outer.end_price = quotes_h[pos.expires_on.to_s][pos.put_call][pos.outer.strike][:price]
|
|
245
|
+
pos.outer.end_delta = quotes_h[pos.expires_on.to_s][pos.put_call][pos.outer.strike][:delta]
|
|
246
|
+
pos.outer.save ? print('^') : print('X')
|
|
247
|
+
end
|
|
248
|
+
count = count+1
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
print 'synced-all.'
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
|
|
211
255
|
|
|
212
256
|
##
|
|
213
257
|
## decisions
|
|
@@ -230,7 +274,7 @@ class Iro::Position
|
|
|
230
274
|
|
|
231
275
|
def calc_nxt
|
|
232
276
|
pos = self
|
|
233
|
-
puts! pos, '#calc_nxt...'
|
|
277
|
+
# puts! pos, '#calc_nxt...'
|
|
234
278
|
|
|
235
279
|
## 7 days ahead - not configurable
|
|
236
280
|
params = {
|
|
@@ -238,11 +282,16 @@ class Iro::Position
|
|
|
238
282
|
expirationDate: next_expires_on,
|
|
239
283
|
ticker: ticker,
|
|
240
284
|
}
|
|
241
|
-
puts! params, 'ze params'
|
|
285
|
+
# puts! params, 'ze params'
|
|
242
286
|
outs = Tda::Option.get_quotes(params)
|
|
243
|
-
puts! outs, 'outs'
|
|
287
|
+
# puts! outs, 'outs'
|
|
244
288
|
outs_bk = outs.dup
|
|
245
289
|
|
|
290
|
+
## cleanup mid-increments
|
|
291
|
+
outs = outs.select do |out|
|
|
292
|
+
( out[:strikePrice] - pos.inner.strike ) % strategy.stock.options_price_increment == 0
|
|
293
|
+
end
|
|
294
|
+
|
|
246
295
|
outs = outs.select do |out|
|
|
247
296
|
out[:bidSize] + out[:askSize] > 0
|
|
248
297
|
end
|
|
@@ -269,7 +318,7 @@ class Iro::Position
|
|
|
269
318
|
raise 'zt3 - @TODO: implement, debit spreads'
|
|
270
319
|
end
|
|
271
320
|
end
|
|
272
|
-
puts! outs[0][:strikePrice], 'after calc next_inner_strike'
|
|
321
|
+
# puts! outs[0][:strikePrice], 'after calc next_inner_strike'
|
|
273
322
|
# puts! outs, 'outs'
|
|
274
323
|
end
|
|
275
324
|
|
|
@@ -283,23 +332,16 @@ class Iro::Position
|
|
|
283
332
|
raise 'zt4 - this cannot happen'
|
|
284
333
|
end
|
|
285
334
|
end
|
|
286
|
-
puts! outs[0][:strikePrice], 'after calc next_usd_above_mark'
|
|
287
|
-
puts! outs, 'outs'
|
|
335
|
+
# puts! outs[0][:strikePrice], 'after calc next_usd_above_mark'
|
|
336
|
+
# puts! outs, 'outs'
|
|
288
337
|
|
|
289
338
|
## next_inner_delta
|
|
290
339
|
outs = outs.select do |out|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
out_delta <= strategy.next_inner_delta
|
|
294
|
-
elsif 'PUT' == pos.put_call
|
|
295
|
-
out_delta = out[:delta] rescue 0
|
|
296
|
-
out_delta <= strategy.next_inner_delta
|
|
297
|
-
else
|
|
298
|
-
raise 'zt5 - this cannot happen'
|
|
299
|
-
end
|
|
340
|
+
out_delta = out[:delta].abs rescue 0
|
|
341
|
+
out_delta <= strategy.next_inner_delta
|
|
300
342
|
end
|
|
301
|
-
puts! outs[0][:strikePrice], 'after calc next_inner_delta'
|
|
302
|
-
puts! outs, 'outs'
|
|
343
|
+
# puts! outs[0][:strikePrice], 'after calc next_inner_delta'
|
|
344
|
+
# puts! outs, 'outs'
|
|
303
345
|
|
|
304
346
|
inner = outs[0]
|
|
305
347
|
outs = outs.select do |out|
|
|
@@ -393,13 +435,13 @@ class Iro::Position
|
|
|
393
435
|
out = "#{stock} (#{q}) #{expires_on.to_datetime.strftime('%b %d')} #{strategy.long_or_short} ["
|
|
394
436
|
if Iro::Strategy::LONG == long_or_short
|
|
395
437
|
if outer&.strike
|
|
396
|
-
out = out + "$#{outer.strike}
|
|
438
|
+
out = out + "$#{outer.strike} << "
|
|
397
439
|
end
|
|
398
440
|
out = out + "$#{inner.strike}"
|
|
399
441
|
else
|
|
400
442
|
out = out + "$#{inner.strike}"
|
|
401
443
|
if outer&.strike
|
|
402
|
-
out = out + "
|
|
444
|
+
out = out + " >> $#{outer.strike}"
|
|
403
445
|
end
|
|
404
446
|
end
|
|
405
447
|
out += "] "
|
data/app/models/iro/purse.rb
CHANGED
data/app/models/iro/strategy.rb
CHANGED
|
@@ -94,11 +94,19 @@ class Iro::Strategy
|
|
|
94
94
|
field :next_usd_above_mark, type: :float
|
|
95
95
|
validates :next_usd_above_mark, presence: true
|
|
96
96
|
|
|
97
|
+
|
|
97
98
|
INTENT_CLOSE = 'try-close'
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
INTENT_OPEN = 'try-open'
|
|
100
|
+
INTENT_ROLL = 'try-roll'
|
|
101
|
+
INTENTS = [ nil, INTENT_CLOSE, INTENT_ROLL ]
|
|
100
102
|
field :intent
|
|
101
103
|
|
|
104
|
+
field :sentiment, type: :float
|
|
105
|
+
field :sentiment_sector, type: :float
|
|
106
|
+
field :sentiment_market, type: :float
|
|
107
|
+
|
|
108
|
+
field :tgt_exposure, type: :float
|
|
109
|
+
|
|
102
110
|
|
|
103
111
|
def begin_delta_covered_call p
|
|
104
112
|
p.inner.begin_delta
|
|
@@ -330,7 +338,7 @@ class Iro::Strategy
|
|
|
330
338
|
## 2026-02-21 ok
|
|
331
339
|
## 2026-04-05 ok
|
|
332
340
|
def calc_rollp_short_credit_call_spread p
|
|
333
|
-
puts! p, 'calc_rollp_short_credit_call_spread...'
|
|
341
|
+
# puts! p, 'calc_rollp_short_credit_call_spread...'
|
|
334
342
|
stock.reload
|
|
335
343
|
|
|
336
344
|
if ( p.expires_on.to_date - Time.now.to_date ).to_i <= threshold_dte
|
|
@@ -371,7 +379,7 @@ class Iro::Strategy
|
|
|
371
379
|
|
|
372
380
|
|
|
373
381
|
def to_s
|
|
374
|
-
"#{kind} #{stock} #{next_spread_amount}- #{intent}
|
|
382
|
+
"#{kind} #{stock} #{next_spread_amount}- #{intent} #{descr}"
|
|
375
383
|
end
|
|
376
384
|
def self.list long_or_short = nil
|
|
377
385
|
these = long_or_short ? where( long_or_short: long_or_short ) : all
|
data/app/models/tda/option.rb
CHANGED
|
@@ -12,7 +12,7 @@ end
|
|
|
12
12
|
class Tda::Option
|
|
13
13
|
|
|
14
14
|
include ::HTTParty
|
|
15
|
-
debug_output $stdout
|
|
15
|
+
# debug_output $stdout
|
|
16
16
|
base_uri 'https://api.schwabapi.com/marketdata/v1'
|
|
17
17
|
|
|
18
18
|
|
|
@@ -43,7 +43,7 @@ class Tda::Option
|
|
|
43
43
|
query: query }
|
|
44
44
|
timestamp = DateTime.parse out.headers['date']
|
|
45
45
|
out = out.parsed_response
|
|
46
|
-
puts! out, 'outs'
|
|
46
|
+
# puts! out, 'outs'
|
|
47
47
|
|
|
48
48
|
outs = []
|
|
49
49
|
%w| put call |.each do |contractType|
|
|
@@ -109,7 +109,7 @@ class Tda::Option
|
|
|
109
109
|
## 2023-02-06 _vp_ :: Continue.
|
|
110
110
|
##
|
|
111
111
|
def self.get_quotes params
|
|
112
|
-
puts! params, 'core Tda::Option#get_quotes...'
|
|
112
|
+
# puts! params, 'core Tda::Option#get_quotes...'
|
|
113
113
|
|
|
114
114
|
profile = Wco::Profile.find_by email: 'piousbox@gmail.com'
|
|
115
115
|
opts = {}
|
|
@@ -178,7 +178,7 @@ class Tda::Option
|
|
|
178
178
|
|
|
179
179
|
## 2026-02-23 use this instead.
|
|
180
180
|
def self.get_quotes_h params
|
|
181
|
-
puts! params, 'Tda::Option#get_quotes_h ...'
|
|
181
|
+
# puts! params, 'Tda::Option#get_quotes_h ...'
|
|
182
182
|
|
|
183
183
|
profile = Wco::Profile.find_by email: 'piousbox@gmail.com'
|
|
184
184
|
opts = {}
|
|
@@ -214,7 +214,7 @@ class Tda::Option
|
|
|
214
214
|
|
|
215
215
|
## query = { contractType: "PUT", toDate: "2026-02-26", fromDate: "2026-02-26", symbol: "TSLA", strike: 395.0}
|
|
216
216
|
query = { }.merge opts
|
|
217
|
-
puts! query, 'query'
|
|
217
|
+
# puts! query, 'query'
|
|
218
218
|
|
|
219
219
|
results = self.get( "/chains", {
|
|
220
220
|
headers: {
|
|
@@ -296,7 +296,7 @@ class Tda::Option
|
|
|
296
296
|
],
|
|
297
297
|
}
|
|
298
298
|
File.write('tmp/query.json', JSON.pretty_generate( query ))
|
|
299
|
-
puts! query, 'query'
|
|
299
|
+
# puts! query, 'query'
|
|
300
300
|
|
|
301
301
|
return
|
|
302
302
|
|
|
@@ -305,11 +305,11 @@ class Tda::Option
|
|
|
305
305
|
}
|
|
306
306
|
|
|
307
307
|
path = "/v1/accounts/#{::TD_AMERITRADE[:accountId]}/orders"
|
|
308
|
-
puts! path, 'path'
|
|
308
|
+
# puts! path, 'path'
|
|
309
309
|
out = self.post path, { query: query, headers: headers }
|
|
310
310
|
timestamp = DateTime.parse out.headers['date']
|
|
311
311
|
out = out.parsed_response.deep_symbolize_keys
|
|
312
|
-
puts! out, 'created credit call?'
|
|
312
|
+
# puts! out, 'created credit call?'
|
|
313
313
|
end
|
|
314
314
|
def self.create_long_debit_call_spread
|
|
315
315
|
end
|
data/app/models/tda/order.rb
CHANGED
|
@@ -98,10 +98,10 @@ class Tda::Order
|
|
|
98
98
|
return query
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
-
## open credit spread
|
|
101
|
+
## open credit spread
|
|
102
102
|
def self.credit_spread_q pos
|
|
103
103
|
query = {
|
|
104
|
-
orderType: pos.
|
|
104
|
+
orderType: pos.pending_price > 0 ? "NET_CREDIT" : "NET_DEBIT",
|
|
105
105
|
session: "NORMAL",
|
|
106
106
|
duration: "DAY",
|
|
107
107
|
price: pos.pending_price,
|
|
@@ -190,10 +190,10 @@ class Tda::Order
|
|
|
190
190
|
|
|
191
191
|
def self.roll_credit_call_spread_q pos
|
|
192
192
|
query = {
|
|
193
|
-
orderType: pos.
|
|
193
|
+
orderType: pos.pending_price > 0 ? "NET_CREDIT" : "NET_DEBIT",
|
|
194
194
|
session: "NORMAL",
|
|
195
195
|
duration: "DAY",
|
|
196
|
-
price: pos.
|
|
196
|
+
price: pos.pending_price.abs.to_s,
|
|
197
197
|
orderStrategyType: "SINGLE",
|
|
198
198
|
orderLegCollection: [
|
|
199
199
|
## close
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: wco_models
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.1.0.
|
|
4
|
+
version: 3.1.0.270
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Victor Pudeyev
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ahoy_matey
|