wco_models 3.1.0.263 → 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: 74411b5f6d7e9b1d2c6de54a15dc3438e00440d48220f545e7c6088fd2c6b519
4
- data.tar.gz: 95a99dc3e85cd510fe4aeb0c5a6233e105691953231eeecbeeb1bef75460e292
3
+ metadata.gz: 327c2ab838cce926d5afd9e979b7acb2979aa8e78d1745470ea29ccac2e81197
4
+ data.tar.gz: 42615e28beeb55afbdf91eb592c58b22dae4a89d168e2ba17ce9046a7ac68857
5
5
  SHA512:
6
- metadata.gz: b1219a5f7c28b3b828c32db3357c40f9e4974470769dc65a11ee9580ffb5b26fa033d28a8d033ab9424c26a45f556ca2e134628cc963e5aae25254c300f4439c
7
- data.tar.gz: fdd901493b1083ed8818bcf5c88e55766b2b1e6f008aa26d28fff389c008a61e205a9c37c52908c981f49a82ee0a15189aa76b249fde88011fca84b5ed32434b
6
+ metadata.gz: 9ca18a2f3190d96d1c8a2d9b62823886b8bb77870b22246a4af13f1f55081c65dd8bfc7b15e0db9fd232d0efc0968c7c4dd0ac8c9e0da1063c486b08fe2c5d9c
7
+ data.tar.gz: 8c4c8a85bcd9087b837e6c70b42082967c9b2d502c9cc12651a946cceab10c6d85ca1d18646fa18f6b56862b51cd8436e9071a7eaa8bda059dbd6a1252cd65b3
@@ -70,18 +70,6 @@ table.bordered {
70
70
  }
71
71
  }
72
72
 
73
- table {
74
- thead.sticky {
75
- background: #ccc;
76
-
77
- th {
78
- position: sticky;
79
- top: 0;
80
- background: white;
81
- z-index: 10;
82
- }
83
- }
84
- }
85
73
 
86
74
  /* C */
87
75
 
@@ -95,6 +83,11 @@ textarea.monospace {
95
83
  padding: 0.6em;
96
84
  }
97
85
 
86
+ .crossed,
87
+ .crossout {
88
+ text-decoration: line-through;
89
+ }
90
+
98
91
  /* D */
99
92
 
100
93
  .d-flex {
@@ -252,10 +245,36 @@ label.required {
252
245
 
253
246
 
254
247
  /* S */
248
+
255
249
  .spacer-small {
256
250
  height: 20px;
257
251
  }
258
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
+
259
278
  /* T */
260
279
 
261
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,
@@ -14,8 +14,7 @@ class Iro::Purse
14
14
 
15
15
  has_many :positions, class_name: 'Iro::Position', inverse_of: :purse
16
16
 
17
- # has_and_belongs_to_many :strategies, class_name: 'Iro::Strategy', inverse_of: :purses
18
- # belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :strategies
17
+ has_many :strategies, class_name: 'Iro::Strategy', inverse_of: :purse
19
18
 
20
19
  field :unit, type: :integer, default: 10
21
20
  ## with unit 10, .001
@@ -34,35 +33,6 @@ class Iro::Purse
34
33
  available_amount
35
34
  end
36
35
 
37
- # def balance
38
- # 0.01
39
- # end
40
-
41
- def delta_wt_avg( begin_end, long_short, inner_outer )
42
- max_loss_total = 0
43
-
44
- out = positions.send( long_short ).map do |pos|
45
- max_loss_total += pos.max_loss * pos.q
46
- pos.max_loss * pos.q * pos.send( inner_outer ).send( "#{begin_end}_delta" )
47
- end
48
- # puts! out, 'delta_wt_avg 1'
49
- out = out.reduce( &:+ ) / max_loss_total rescue 0
50
- # puts! out, 'delta_wt_avg 2'
51
- return out
52
- end
53
- ## delta to plot percentage
54
- ## convert to normal between 0 and 3 std
55
- def delta_to_plot_p( *args )
56
- x = delta_wt_avg( *args ).abs
57
- if x < 0.5
58
- y = 1
59
- else
60
- y = 2 - 1/( 1.5 - x )
61
- end
62
- y_ = "#{ (y*100) .to_i}%"
63
- return y_
64
- end
65
-
66
36
  def to_s
67
37
  slug
68
38
  end
@@ -5,7 +5,7 @@ class Iro::Strategy
5
5
  include Mongoid::Paranoia
6
6
  store_in collection: 'iro_strategies'
7
7
 
8
- field :description
8
+ field :descr
9
9
 
10
10
  LONG = 'long'
11
11
  SHORT = 'short'
@@ -17,11 +17,11 @@ class Iro::Strategy
17
17
  field :credit_or_debit, type: :string, default: 'credit'
18
18
  validates :credit_or_debit, presence: true
19
19
 
20
-
21
20
  has_many :positions, class_name: 'Iro::Position', inverse_of: :strategy, dependent: :destroy
22
- has_one :next_position, class_name: 'Iro::Position', inverse_of: :next_strategy ## _TODO: makes no sense...
21
+ ## _TODO: makes no sense...
22
+ has_one :next_position, class_name: 'Iro::Position', inverse_of: :next_strategy
23
23
  belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :strategies
24
- # has_and_belongs_to_many :purses, class_name: 'Iro::Purse', inverse_of: :strategies
24
+ belongs_to :purse, class_name: 'Iro::Purse', inverse_of: :strategies
25
25
 
26
26
  KIND_COVERED_CALL = 'covered_call'
27
27
  KIND_IRON_CONDOR = 'iron_condor'
@@ -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
@@ -87,14 +86,13 @@ class Iro::Strategy
87
86
  field :threshold_dte, type: :integer, default: 1
88
87
 
89
88
  field :next_inner_delta, type: :float
90
- field :next_inner_strike, type: :float
89
+ field :next_inner_strike, type: :float ## can be nil, poor design?
91
90
  field :next_outer_delta, type: :float
92
91
  field :next_outer_strike, type: :float
93
92
  field :next_spread_amount, type: :float # e.g. $20 for a $2000 NVDA spread
94
93
 
95
- field :next_threshold_usd_above_mark, type: :float
96
- validates :next_threshold_usd_above_mark, presence: true
97
- def next_buffer_above_water; next_threshold_usd_above_mark; end
94
+ field :next_usd_above_mark, type: :float
95
+ validates :next_usd_above_mark, presence: true
98
96
 
99
97
  def begin_delta_covered_call p
100
98
  p.inner.begin_delta
@@ -207,6 +205,7 @@ class Iro::Strategy
207
205
  ## decisions
208
206
  ##
209
207
 
208
+ ## do not use!
210
209
  def calc_rollp_covered_call p
211
210
  stock.reload
212
211
 
@@ -214,10 +213,10 @@ class Iro::Strategy
214
213
  return [ 0.99, '0 DTE, must exit' ]
215
214
  end
216
215
 
217
- if ( stock.last - buffer_above_water ) < p.inner.strike
216
+ if ( stock.last - threshold_usd_above_mark ) < p.inner.strike
218
217
  return [ 0.98, "Last #{'%.2f' % stock.last} is " +
219
- "#{'%.2f' % [p.inner.strike + buffer_above_water - stock.last]} " +
220
- "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" ]
221
220
  end
222
221
 
223
222
  if p.inner.end_delta < threshold_pos_delta
@@ -231,7 +230,7 @@ class Iro::Strategy
231
230
  return [ 0.33, '-' ]
232
231
  end
233
232
 
234
- ## _TODO
233
+ ## do not use!
235
234
  def calc_rollp_long_debit_call_spread p
236
235
  stock.reload
237
236
 
@@ -242,10 +241,10 @@ class Iro::Strategy
242
241
  return [ 0.99, '1 DTE, must exit' ]
243
242
  end
244
243
 
245
- if ( stock.last - buffer_above_water ) < p.inner.strike
244
+ if ( stock.last - threshold_usd_above_mark ) < p.inner.strike
246
245
  return [ 0.95, "Last #{'%.2f' % stock.last} is " +
247
- "#{'%.2f' % [stock.last - p.inner.strike - buffer_above_water]} " +
248
- "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" ]
249
248
  end
250
249
 
251
250
  if p.inner.end_delta < threshold_pos_delta
@@ -259,14 +258,15 @@ class Iro::Strategy
259
258
  return [ 0.33, '-' ]
260
259
  end
261
260
 
262
- ## 2025-10-12 _TODO
261
+ ## 2025-10-12 continue
262
+ ## 2026-04-05 continue
263
263
  def calc_rollp_long_credit_put_spread p
264
264
  stock.reload
265
265
 
266
266
  # puts! p, '#calc_rollp_long_credit_put_spread'
267
267
  # puts! p.inner, 'p.inner'
268
- puts! stock, 'stock'
269
- puts! attributes, 'strategy attributes'
268
+ # puts! stock, 'stock'
269
+ # puts! attributes, 'strategy attributes'
270
270
 
271
271
  if ( p.expires_on.to_date - Time.now.to_date ).to_i < 1
272
272
  return [ 0.99, '0 DTE, must exit' ]
@@ -275,24 +275,28 @@ class Iro::Strategy
275
275
  return [ 0.99, '1 DTE, must exit' ]
276
276
  end
277
277
 
278
- if ( stock.last - buffer_above_water ) < p.inner.strike
279
- return [ 0.95, "Last #{'%.2f' % stock.last} is " +
280
- "#{'%.2f' % [stock.last - p.inner.strike - buffer_above_water]} " +
281
- "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} ." ]
282
281
  end
283
282
 
284
- if p.inner.end_delta < threshold_pos_delta
285
- 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} ." ]
286
288
  end
287
289
 
288
- if 1 - p.inner.end_price/p.inner.begin_price > threshold_netp
289
- 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
290
294
  end
291
295
 
292
296
  return [ 0.33, '-' ]
293
297
  end
294
298
 
295
- ## _TODO
299
+ ## do not use!
296
300
  def calc_rollp_short_debit_put_spread p
297
301
  stock.reload
298
302
 
@@ -300,10 +304,10 @@ class Iro::Strategy
300
304
  return [ 0.99, "< #{threshold_dte}DTE, must exit" ]
301
305
  end
302
306
 
303
- if stock.last + buffer_above_water > p.inner.strike
307
+ if stock.last + threshold_usd_above_mark > p.inner.strike
304
308
  return [ 0.98, "Last #{'%.2f' % stock.last} is " +
305
- "#{'%.2f' % [stock.last + buffer_above_water - p.inner.strike]} " +
306
- "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" ]
307
311
  end
308
312
 
309
313
  if p.inner.end_delta.abs < threshold_pos_delta.abs
@@ -318,6 +322,7 @@ class Iro::Strategy
318
322
  end
319
323
 
320
324
  ## 2026-02-21 ok
325
+ ## 2026-04-05 ok
321
326
  def calc_rollp_short_credit_call_spread p
322
327
  puts! p, 'calc_rollp_short_credit_call_spread...'
323
328
  stock.reload
@@ -326,10 +331,9 @@ class Iro::Strategy
326
331
  return [ 0.99, "< #{threshold_dte}DTE, must exit" ]
327
332
  end
328
333
 
329
- if stock.last + buffer_above_water > p.inner.strike
330
- return [ 0.95, "Last #{'%.2f' % stock.last} is " +
331
- "#{'%.2f' % [stock.last + buffer_above_water - p.inner.strike]} " +
332
- "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} ." ]
333
337
  end
334
338
 
335
339
  ## defensive
@@ -343,8 +347,10 @@ class Iro::Strategy
343
347
  return [ 0.69, "Delta #{p.inner.end_delta} is lower than #{threshold_pos_delta} offensive threshold." ]
344
348
  end
345
349
 
346
- if p.net_percent > threshold_netp
347
- 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
348
354
  end
349
355
 
350
356
  return [ 0.33, '-' ]
@@ -362,7 +368,7 @@ class Iro::Strategy
362
368
  # "#{kind} #{stock}"
363
369
  # end
364
370
  def to_s
365
- "#{kind} #{stock}"
371
+ "#{kind} #{stock} #{descr}"
366
372
  end
367
373
  def self.list long_or_short = nil
368
374
  these = long_or_short ? where( long_or_short: long_or_short ) : all
@@ -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
@@ -18,11 +18,14 @@
18
18
 
19
19
  .field
20
20
  %label leadset
21
- = f.select :leadset, options_for_select(Wco::Leadset.list, selected: profile.leadset_id )
21
+ = f.select :leadset, options_for_select(Wco::Leadset.list, selected: profile.leadset_id ), {}, { class: 'select2' }
22
22
 
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.263
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