wco_models 3.1.0.264 → 3.1.0.265

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: 06f4f98ee3c36e42af419ef0778c2b1dcef99b45b6950a0b8e0847e4f122ab84
4
- data.tar.gz: 3156138556995606ce6c338af1fc675b678da32a6c4a2996e3c1c6c6fc8096e8
3
+ metadata.gz: 327c2ab838cce926d5afd9e979b7acb2979aa8e78d1745470ea29ccac2e81197
4
+ data.tar.gz: 42615e28beeb55afbdf91eb592c58b22dae4a89d168e2ba17ce9046a7ac68857
5
5
  SHA512:
6
- metadata.gz: 3fdab086ab82d058301d86f1b85fac771df0fbedac5418ff503218b04d960cd09ca2a73bebee5aaee4a57f9a910b259b0ea046d5224a62790286108370c863ee
7
- data.tar.gz: 82e604c3c74303c03b7db2a007f1ddb0e6725d77957c86355ca0e749af9b7dadd7d6e6e15d2f2d3528e22d72ddd5f2387e6e9b5a061118801810955613215e2f
6
+ metadata.gz: 9ca18a2f3190d96d1c8a2d9b62823886b8bb77870b22246a4af13f1f55081c65dd8bfc7b15e0db9fd232d0efc0968c7c4dd0ac8c9e0da1063c486b08fe2c5d9c
7
+ data.tar.gz: 8c4c8a85bcd9087b837e6c70b42082967c9b2d502c9cc12651a946cceab10c6d85ca1d18646fa18f6b56862b51cd8436e9071a7eaa8bda059dbd6a1252cd65b3
@@ -70,16 +70,6 @@ table.bordered {
70
70
  }
71
71
  }
72
72
 
73
- table.sticky thead,
74
- table thead.sticky {
75
- background: #ccc;
76
-
77
- th {
78
- position: sticky;
79
- top: 0;
80
- z-index: 10;
81
- }
82
- }
83
73
 
84
74
  /* C */
85
75
 
@@ -93,6 +83,11 @@ textarea.monospace {
93
83
  padding: 0.6em;
94
84
  }
95
85
 
86
+ .crossed,
87
+ .crossout {
88
+ text-decoration: line-through;
89
+ }
90
+
96
91
  /* D */
97
92
 
98
93
  .d-flex {
@@ -250,10 +245,36 @@ label.required {
250
245
 
251
246
 
252
247
  /* S */
248
+
253
249
  .spacer-small {
254
250
  height: 20px;
255
251
  }
256
252
 
253
+ div.sticky,
254
+ h2.sticky,
255
+ h3.sticky,
256
+ h4.sticky,
257
+ h5.sticky {
258
+ position: sticky;
259
+ top: 0.5em;
260
+ z-index: 10;
261
+
262
+ border-radius: 0.5em;
263
+ padding: 0.5em;
264
+ background: rgba(255,255,255, 0.5);
265
+ }
266
+
267
+ table.sticky thead,
268
+ table thead.sticky {
269
+ background: #ccc;
270
+
271
+ th {
272
+ position: sticky;
273
+ top: 0;
274
+ z-index: 10;
275
+ }
276
+ }
277
+
257
278
  /* T */
258
279
 
259
280
  .title {
@@ -34,8 +34,8 @@ module Wco::ApplicationHelper
34
34
  end
35
35
 
36
36
  def pp_amount a, config = { precision: 2 }
37
- return '-' if !a
38
- return '-' if a.class == String
37
+ return '___' if !a
38
+ return '___' if a.class == String
39
39
  return number_to_currency a, precision: config[:precision]
40
40
  # "$#{'%.2f' % a}"
41
41
  end
@@ -5,12 +5,6 @@ class Iro::Position
5
5
  include Mongoid::Paranoia
6
6
  store_in collection: 'iro_positions'
7
7
 
8
- ## @trash, use next_gain_loss_amount instead
9
- # field :prev_gain_loss_amount, type: :float
10
- # def prev_gain_loss_amount
11
- # out = autoprev.outer.end_price - autoprev.inner.end_price
12
- # out += inner.begin_price - outer.begin_price
13
- # end
14
8
  field :next_gain_loss_amount, type: :float
15
9
 
16
10
 
@@ -231,33 +225,35 @@ class Iro::Position
231
225
  # puts! outs, '#calc_nxt.outs -> 2'
232
226
 
233
227
  ## next_inner_strike
234
- outs = outs.select do |out|
235
- if Iro::Strategy::CREDIT == pos.credit_or_debit
236
- if Iro::Strategy::SHORT == pos.long_or_short
237
- ## short credit call
238
- out[:strikePrice] >= strategy.next_inner_strike
239
- elsif Iro::Strategy::LONG == pos.long_or_short
240
- ## long credit put
241
- out[:strikePrice] <= strategy.next_inner_strike
228
+ if strategy.next_inner_strike.present?
229
+ outs = outs.select do |out|
230
+ if Iro::Strategy::CREDIT == pos.credit_or_debit
231
+ if Iro::Strategy::SHORT == pos.long_or_short
232
+ ## short credit call
233
+ out[:strikePrice] >= strategy.next_inner_strike
234
+ elsif Iro::Strategy::LONG == pos.long_or_short
235
+ ## long credit put
236
+ out[:strikePrice] <= strategy.next_inner_strike
237
+ end
238
+ else
239
+ raise 'zt3 - @TODO: implement, debit spreads'
242
240
  end
243
- else
244
- raise 'zt3 - @TODO: implement, debit spreads'
245
241
  end
242
+ puts! outs[0][:strikePrice], 'after calc next_inner_strike'
243
+ # puts! outs, 'outs'
246
244
  end
247
- puts! outs[0][:strikePrice], 'after calc next_inner_strike'
248
- # puts! outs, 'outs'
249
245
 
250
- ## next_buffer_above_water
246
+ ## next_usd_above_mark
251
247
  outs = outs.select do |out|
252
248
  if Iro::Strategy::SHORT == pos.long_or_short
253
- out[:strikePrice] > strategy.next_buffer_above_water + strategy.stock.last
249
+ out[:strikePrice] > strategy.next_usd_above_mark + strategy.stock.last
254
250
  elsif Iro::Strategy::LONG == pos.long_or_short
255
- out[:strikePrice] < strategy.stock.last - strategy.next_buffer_above_water
251
+ out[:strikePrice] < strategy.stock.last - strategy.next_usd_above_mark
256
252
  else
257
253
  raise 'zt4 - this cannot happen'
258
254
  end
259
255
  end
260
- puts! outs[0][:strikePrice], 'after calc next_buffer_above_water'
256
+ puts! outs[0][:strikePrice], 'after calc next_usd_above_mark'
261
257
  puts! outs, 'outs'
262
258
 
263
259
  ## next_inner_delta
@@ -310,7 +306,9 @@ class Iro::Position
310
306
  status: 'proposed',
311
307
  stock: strategy.stock,
312
308
  inner_strike: inner_attrs[:strike],
309
+ inner_attributes: inner_attrs,
313
310
  outer_strike: outer_attrs[:strike],
311
+ outer_attributes: outer_attrs,
314
312
  begin_on: Time.now.to_date,
315
313
  expires_on: next_expires_on,
316
314
  purse: purse,
@@ -33,35 +33,6 @@ class Iro::Purse
33
33
  available_amount
34
34
  end
35
35
 
36
- # def balance
37
- # 0.01
38
- # end
39
-
40
- def delta_wt_avg( begin_end, long_short, inner_outer )
41
- max_loss_total = 0
42
-
43
- out = positions.send( long_short ).map do |pos|
44
- max_loss_total += pos.max_loss * pos.q
45
- pos.max_loss * pos.q * pos.send( inner_outer ).send( "#{begin_end}_delta" )
46
- end
47
- # puts! out, 'delta_wt_avg 1'
48
- out = out.reduce( &:+ ) / max_loss_total rescue 0
49
- # puts! out, 'delta_wt_avg 2'
50
- return out
51
- end
52
- ## delta to plot percentage
53
- ## convert to normal between 0 and 3 std
54
- def delta_to_plot_p( *args )
55
- x = delta_wt_avg( *args ).abs
56
- if x < 0.5
57
- y = 1
58
- else
59
- y = 2 - 1/( 1.5 - x )
60
- end
61
- y_ = "#{ (y*100) .to_i}%"
62
- return y_
63
- end
64
-
65
36
  def to_s
66
37
  slug
67
38
  end
@@ -79,7 +79,6 @@ class Iro::Strategy
79
79
 
80
80
  field :threshold_usd_above_mark, type: :float
81
81
  validates :threshold_usd_above_mark, presence: true
82
- def buffer_above_water; threshold_usd_above_mark; end
83
82
 
84
83
  field :threshold_pos_delta, type: :float # offensive: roll b/c markets are going my way
85
84
  field :threshold_neg_delta, type: :float # defensive: roll b/c markets are going against me
@@ -206,6 +205,7 @@ class Iro::Strategy
206
205
  ## decisions
207
206
  ##
208
207
 
208
+ ## do not use!
209
209
  def calc_rollp_covered_call p
210
210
  stock.reload
211
211
 
@@ -213,10 +213,10 @@ class Iro::Strategy
213
213
  return [ 0.99, '0 DTE, must exit' ]
214
214
  end
215
215
 
216
- if ( stock.last - buffer_above_water ) < p.inner.strike
216
+ if ( stock.last - threshold_usd_above_mark ) < p.inner.strike
217
217
  return [ 0.98, "Last #{'%.2f' % stock.last} is " +
218
- "#{'%.2f' % [p.inner.strike + buffer_above_water - stock.last]} " +
219
- "below #{'%.2f' % [p.inner.strike + buffer_above_water]} water" ]
218
+ "#{'%.2f' % [p.inner.strike + threshold_usd_above_mark - stock.last]} " +
219
+ "below #{'%.2f' % [p.inner.strike + threshold_usd_above_mark]} water" ]
220
220
  end
221
221
 
222
222
  if p.inner.end_delta < threshold_pos_delta
@@ -230,7 +230,7 @@ class Iro::Strategy
230
230
  return [ 0.33, '-' ]
231
231
  end
232
232
 
233
- ## _TODO
233
+ ## do not use!
234
234
  def calc_rollp_long_debit_call_spread p
235
235
  stock.reload
236
236
 
@@ -241,10 +241,10 @@ class Iro::Strategy
241
241
  return [ 0.99, '1 DTE, must exit' ]
242
242
  end
243
243
 
244
- if ( stock.last - buffer_above_water ) < p.inner.strike
244
+ if ( stock.last - threshold_usd_above_mark ) < p.inner.strike
245
245
  return [ 0.95, "Last #{'%.2f' % stock.last} is " +
246
- "#{'%.2f' % [stock.last - p.inner.strike - buffer_above_water]} " +
247
- "below #{'%.2f' % [p.inner.strike + buffer_above_water]} water" ]
246
+ "#{'%.2f' % [stock.last - p.inner.strike - threshold_usd_above_mark]} " +
247
+ "below #{'%.2f' % [p.inner.strike + threshold_usd_above_mark]} water" ]
248
248
  end
249
249
 
250
250
  if p.inner.end_delta < threshold_pos_delta
@@ -258,14 +258,15 @@ class Iro::Strategy
258
258
  return [ 0.33, '-' ]
259
259
  end
260
260
 
261
- ## 2025-10-12 _TODO
261
+ ## 2025-10-12 continue
262
+ ## 2026-04-05 continue
262
263
  def calc_rollp_long_credit_put_spread p
263
264
  stock.reload
264
265
 
265
266
  # puts! p, '#calc_rollp_long_credit_put_spread'
266
267
  # puts! p.inner, 'p.inner'
267
- puts! stock, 'stock'
268
- puts! attributes, 'strategy attributes'
268
+ # puts! stock, 'stock'
269
+ # puts! attributes, 'strategy attributes'
269
270
 
270
271
  if ( p.expires_on.to_date - Time.now.to_date ).to_i < 1
271
272
  return [ 0.99, '0 DTE, must exit' ]
@@ -274,24 +275,28 @@ class Iro::Strategy
274
275
  return [ 0.99, '1 DTE, must exit' ]
275
276
  end
276
277
 
277
- if ( stock.last - buffer_above_water ) < p.inner.strike
278
- return [ 0.95, "Last #{'%.2f' % stock.last} is " +
279
- "#{'%.2f' % [stock.last - p.inner.strike - buffer_above_water]} " +
280
- "below #{'%.2f' % [p.inner.strike + buffer_above_water]} water" ]
278
+ if ( stock.last - threshold_usd_above_mark ) < p.inner.strike
279
+ return [ 0.95, ":threshold_usd_above_mark <br />Last $#{'%.2f' % stock.last} is " +
280
+ "#{'%.2f' % [stock.last - p.inner.strike]} near #{p.inner.strike} but should be greater than #{threshold_usd_above_mark} ." ]
281
281
  end
282
282
 
283
- if p.inner.end_delta < threshold_pos_delta
284
- return [ 0.79, "Delta #{p.inner.end_delta} is lower than #{threshold_pos_delta} threshold." ]
283
+ if p.inner.end_delta.abs < threshold_pos_delta
284
+ return [ 0.79, ":threshold_pos_delta <br />Offensive roll: delta #{p.inner.end_delta} is lower than #{threshold_pos_delta} ." ]
285
+ end
286
+ if p.inner.end_delta.abs > threshold_neg_delta
287
+ return [ 0.79, ":threshold_neg_delta <br />Defensive roll: delta #{p.inner.end_delta} is higher than #{threshold_neg_delta} ." ]
285
288
  end
286
289
 
287
- if 1 - p.inner.end_price/p.inner.begin_price > threshold_netp
288
- return [ 0.51, "made enough #{'%.02f' % [(1.0 - p.inner.end_price/p.inner.begin_price )*100]}% profit^" ]
290
+ if threshold_netp.present?
291
+ if 1 - p.inner.end_price/p.inner.begin_price > threshold_netp
292
+ return [ 0.51, ":threshold_netp <br />made enough #{'%.02f' % [(1.0 - p.inner.end_price/p.inner.begin_price )*100]}% profit^" ]
293
+ end
289
294
  end
290
295
 
291
296
  return [ 0.33, '-' ]
292
297
  end
293
298
 
294
- ## _TODO
299
+ ## do not use!
295
300
  def calc_rollp_short_debit_put_spread p
296
301
  stock.reload
297
302
 
@@ -299,10 +304,10 @@ class Iro::Strategy
299
304
  return [ 0.99, "< #{threshold_dte}DTE, must exit" ]
300
305
  end
301
306
 
302
- if stock.last + buffer_above_water > p.inner.strike
307
+ if stock.last + threshold_usd_above_mark > p.inner.strike
303
308
  return [ 0.98, "Last #{'%.2f' % stock.last} is " +
304
- "#{'%.2f' % [stock.last + buffer_above_water - p.inner.strike]} " +
305
- "above #{'%.2f' % [p.inner.strike - buffer_above_water]} water" ]
309
+ "#{'%.2f' % [stock.last + threshold_usd_above_mark - p.inner.strike]} " +
310
+ "above #{'%.2f' % [p.inner.strike - threshold_usd_above_mark]} water" ]
306
311
  end
307
312
 
308
313
  if p.inner.end_delta.abs < threshold_pos_delta.abs
@@ -317,6 +322,7 @@ class Iro::Strategy
317
322
  end
318
323
 
319
324
  ## 2026-02-21 ok
325
+ ## 2026-04-05 ok
320
326
  def calc_rollp_short_credit_call_spread p
321
327
  puts! p, 'calc_rollp_short_credit_call_spread...'
322
328
  stock.reload
@@ -325,10 +331,9 @@ class Iro::Strategy
325
331
  return [ 0.99, "< #{threshold_dte}DTE, must exit" ]
326
332
  end
327
333
 
328
- if stock.last + buffer_above_water > p.inner.strike
329
- return [ 0.95, "Last #{'%.2f' % stock.last} is " +
330
- "#{'%.2f' % [stock.last + buffer_above_water - p.inner.strike]} " +
331
- "above #{'%.2f' % [p.inner.strike - buffer_above_water]} water" ]
334
+ if stock.last + threshold_usd_above_mark > p.inner.strike
335
+ return [ 0.95, ":threshold_usd_above_mark <br />Last $#{'%.2f' % stock.last} is " +
336
+ "#{'%.2f' % [p.inner.strike - stock.last]} near #{p.inner.strike} but should be greater than #{threshold_usd_above_mark} ." ]
332
337
  end
333
338
 
334
339
  ## defensive
@@ -342,8 +347,10 @@ class Iro::Strategy
342
347
  return [ 0.69, "Delta #{p.inner.end_delta} is lower than #{threshold_pos_delta} offensive threshold." ]
343
348
  end
344
349
 
345
- if p.net_percent > threshold_netp
346
- return [ 0.51, "made enough #{'%.0f' % [p.net_percent*100]}% > #{"%.2f" % [threshold_netp*100]}% profit," ]
350
+ if threshold_netp.present?
351
+ if p.net_percent > threshold_netp
352
+ return [ 0.51, "made enough #{'%.0f' % [p.net_percent*100]}% > #{"%.2f" % [threshold_netp*100]}% profit," ]
353
+ end
347
354
  end
348
355
 
349
356
  return [ 0.33, '-' ]
@@ -33,6 +33,7 @@ class Tda::Order
33
33
  puts! results, 'results'
34
34
  end
35
35
 
36
+ ## obsolete, I don't do covered calls anymore?
36
37
  def self.roll_covered_call_q pos
37
38
  roll_price = pos.inner.begin_price - pos.autoprev.inner.end_price
38
39
  query = {
@@ -67,12 +68,12 @@ class Tda::Order
67
68
  return query
68
69
  end
69
70
 
70
- def self.roll_short_credit_call_spread_q pos
71
+ def self.roll_credit_call_spread_q pos
71
72
  query = {
72
- orderType: "NET_CREDIT", ## pos.roll_price > 0 ? "NET_CREDIT" : "NET_DEBIT",
73
+ orderType: pos.roll_price > 0 ? "NET_CREDIT" : "NET_DEBIT",
73
74
  session: "NORMAL",
74
75
  duration: "DAY",
75
- price: ( pos.roll_price + 100 ).to_s, ## _TODO this order will never fill (net credit only)
76
+ price: pos.roll_price.abs.to_s,
76
77
  orderStrategyType: "SINGLE",
77
78
  orderLegCollection: [
78
79
  ## close
@@ -0,0 +1,15 @@
1
+
2
+ class WcoEmail::Config
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ store_in collection: 'wco_email_config'
6
+
7
+ field :key
8
+ validates :key, { presence: true, uniqueness: true }
9
+
10
+ field :value
11
+ validates :value, { presence: true }
12
+
13
+ field :descr
14
+
15
+ end
@@ -23,6 +23,9 @@
23
23
  %hr
24
24
  .row
25
25
  .col-6
26
+ .field
27
+ %label schwab_account_hash
28
+ = f.text_field :schwab_account_hash
26
29
  .field
27
30
  %label schwab_access_token
28
31
  = f.text_field :schwab_access_token
@@ -33,6 +36,8 @@
33
36
  %label schwab_id_token
34
37
  = f.text_field :schwab_id_token
35
38
  .col-6
39
+ .field
40
+ %label &nbsp;
36
41
  .field
37
42
  %label schwab_exec_access_token
38
43
  = f.text_field :schwab_exec_access_token
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.264
4
+ version: 3.1.0.265
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-05 00:00:00.000000000 Z
11
+ date: 2026-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ahoy_matey
@@ -516,6 +516,7 @@ files:
516
516
  - app/models/wco/utils.rb
517
517
  - app/models/wco/video.rb
518
518
  - app/models/wco_email/campaign.rb
519
+ - app/models/wco_email/config.rb
519
520
  - app/models/wco_email/context.rb
520
521
  - app/models/wco_email/conversation.rb
521
522
  - app/models/wco_email/email_action.rb