wco_models 3.1.0.269 → 3.1.0.271

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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.txt +10 -12
  3. data/app/assets/stylesheets/wco/main.scss +24 -0
  4. data/app/assets/stylesheets/wco/newsvideos.scss +45 -0
  5. data/app/controllers/wco/api_controller.rb +2 -2
  6. data/app/controllers/wco/application_controller.rb +45 -0
  7. data/app/controllers/wco/leads_controller.rb +0 -2
  8. data/app/controllers/wco/newspartials_controller.rb +1 -1
  9. data/app/controllers/wco/newsvideos_controller.rb +3 -2
  10. data/app/controllers/wco/publishers_controller.rb +12 -4
  11. data/app/controllers/wco/reports_controller.rb +140 -0
  12. data/app/controllers/wco/tags_controller.rb +18 -5
  13. data/app/controllers/wco/videos_controller.rb +4 -0
  14. data/app/mailers/wco_email/application_mailer.rb +1 -1
  15. data/app/models/ability.rb +3 -0
  16. data/app/models/iro/option.rb +2 -3
  17. data/app/models/iro/position.rb +92 -27
  18. data/app/models/iro/purse.rb +1 -2
  19. data/app/models/iro/stock.rb +20 -0
  20. data/app/models/iro/strategy.rb +57 -40
  21. data/app/models/tda/option.rb +1 -1
  22. data/app/models/tda/order.rb +4 -4
  23. data/app/models/wco/lead.rb +6 -5
  24. data/app/models/wco/newspartial.rb +7 -2
  25. data/app/models/wco/newsvideo.rb +2 -0
  26. data/app/models/wco/photo.rb +2 -0
  27. data/app/models/wco/profile.rb +6 -0
  28. data/app/models/wco/publisher.rb +3 -3
  29. data/app/models/wco/report.rb +6 -3
  30. data/app/models/wco/site.rb +2 -2
  31. data/app/models/wco/tag.rb +3 -0
  32. data/app/models/wco/video.rb +28 -3
  33. data/app/models/wco_email/email_filter.rb +1 -1
  34. data/app/models/wco_email/email_filter_action.rb +2 -0
  35. data/app/models/wco_email/email_filter_condition.rb +29 -14
  36. data/app/models/wco_email/message_stub.rb +2 -1
  37. data/app/views/wco/_main_footer.haml +4 -3
  38. data/app/views/wco/_main_header.haml +1 -0
  39. data/app/views/wco/_sidebar.haml +21 -0
  40. data/app/views/wco/newsoverlays/_show_in_newsvideo.haml +7 -5
  41. data/app/views/wco/newspartials/_show_in_newsvideo.haml +35 -28
  42. data/app/views/wco/newspartials/edit.haml +4 -0
  43. data/app/views/wco/newsvideos/_form.haml +10 -3
  44. data/app/views/wco/newsvideos/show.haml +20 -3
  45. data/app/views/wco/profiles/_form.haml +33 -13
  46. data/app/views/wco/publishers/_post_with.haml +7 -0
  47. data/app/views/wco/reports/_form.haml +11 -2
  48. data/app/views/wco/reports/_to_facebook.html +23 -0
  49. data/app/views/wco/reports/show.haml +15 -0
  50. data/app/views/wco/tags/_index_table.haml +4 -1
  51. data/app/views/wco/tags/_index_tree.haml +2 -1
  52. data/app/views/wco/tags/new_for_sidebar.haml +9 -0
  53. data/app/views/wco/tags/show.haml +54 -42
  54. data/app/views/wco/tags/show.haml-bk +63 -0
  55. data/config/initializers/08_integrations.rb +0 -15
  56. data/config/routes.rb +11 -2
  57. data/lib/wco/facebook_poster.rb +17 -0
  58. metadata +23 -3
  59. data/app/views/wco/newspartials/index.haml-trash +0 -6
@@ -5,7 +5,9 @@ class Iro::Position
5
5
  include Mongoid::Paranoia
6
6
  store_in collection: 'iro_positions'
7
7
 
8
- field :next_gain_loss_amount, type: :float
8
+ field :next_gain_loss_amount, type: :float
9
+ field :realized_gain_loss_amount, type: :float, default: 0.0 ## for diagonals only
10
+ def realized_gl; realized_gain_loss_amount; end
9
11
 
10
12
  STATUS_ACTIVE = 'active'
11
13
  STATUS_CLOSED = 'closed'
@@ -29,6 +31,12 @@ class Iro::Position
29
31
 
30
32
  belongs_to :purse, class_name: 'Iro::Purse', inverse_of: :positions
31
33
  index({ purse_id: 1, ticker: 1 })
34
+ index({ deleted_at: 1,
35
+ status: 1,
36
+ expires_on: 1,
37
+ ticker: 1,
38
+ long_or_short: 1,
39
+ inner_strike: 1 })
32
40
 
33
41
  belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :positions
34
42
  field :ticker
@@ -41,8 +49,13 @@ class Iro::Position
41
49
  end
42
50
 
43
51
  belongs_to :strategy, class_name: 'Iro::Strategy', inverse_of: :positions
44
- delegate :long_or_short, to: :strategy
45
- delegate :credit_or_debit, to: :strategy
52
+ field :long_or_short, type: String
53
+ before_save do
54
+ self.long_or_short = strategy.long_or_short
55
+ end
56
+
57
+ # delegate :credit_or_debit, to: :strategy
58
+ field :credit_or_debit, type: String # , default: 'credit'
46
59
 
47
60
  field :put_call, type: :string
48
61
  validates :put_call, presence: true
@@ -67,9 +80,11 @@ class Iro::Position
67
80
 
68
81
  belongs_to :inner, class_name: 'Iro::Option', inverse_of: :pos_of_inner
69
82
  validates_associated :inner
83
+ has_many :inners, class_name: 'Iro::Option', inverse_of: :poss_of_inner ## for history and diagonals
70
84
 
71
85
  belongs_to :outer, class_name: 'Iro::Option', inverse_of: :pos_of_outer, optional: true
72
86
  validates_associated :outer
87
+ has_many :outers, class_name: 'Iro::Option', inverse_of: :poss_of_outer ## for history and diagonals
73
88
 
74
89
  accepts_nested_attributes_for :inner, :outer
75
90
 
@@ -79,8 +94,12 @@ class Iro::Position
79
94
  field :inner_strike, type: :float
80
95
  validates :inner_strike, presence: true ## 2026-02-24 only to make finding easier.
81
96
 
82
- field :expires_on
97
+ field :expires_on, type: :string
83
98
  validates :expires_on, presence: true
99
+ before_save :trim_expires_on
100
+ def trim_expires_on
101
+ self.expires_on = expires_on.to_s[0, 10] if expires_on.present?
102
+ end
84
103
 
85
104
  field :quantity, type: :integer
86
105
  validates :quantity, presence: true
@@ -93,11 +112,18 @@ class Iro::Position
93
112
  field :schwab_order_id, type: :integer
94
113
  field :schwab_status
95
114
 
115
+ def diag_weeks
116
+ pos = self
117
+ ((pos.outer.expires_on - pos.inner.expires_on)/7).to_i
118
+ end
119
+
96
120
  def begin_delta
97
- strategy.send("begin_delta_#{strategy.kind}", self)
121
+ # strategy.send("begin_delta_#{strategy.kind}", self)
122
+ strategy.begin_delta self
98
123
  end
99
124
  def end_delta
100
- strategy.send("end_delta_#{strategy.kind}", self)
125
+ # strategy.send("end_delta_#{strategy.kind}", self)
126
+ strategy.end_delta self
101
127
  end
102
128
 
103
129
  def breakeven
@@ -116,11 +142,23 @@ class Iro::Position
116
142
  p = self
117
143
  p.inner.strike + p.max_gain
118
144
  end
145
+ def breakeven_short_debit_put_spread
146
+ p = self
147
+ p.inner.strike - p.inner.begin_price + p.outer.begin_price
148
+ end
119
149
  ## 2026-02-23
120
150
  def breakeven_long_credit_put_spread
121
151
  p = self
122
152
  p.inner.strike - p.max_gain
123
153
  end
154
+ def breakeven_diag_long_call_spread
155
+ p = self
156
+ realized_gl + p.outer.strike + p.outer.begin_price - p.inner.begin_price
157
+ end
158
+ def breakeven_diag_short_put_spread
159
+ p = self
160
+ p.inner.strike + p.max_gain + p.realized_gl
161
+ end
124
162
 
125
163
 
126
164
  def current_underlying_strike
@@ -142,7 +180,7 @@ class Iro::Position
142
180
  end
143
181
 
144
182
 
145
- field :pending_price
183
+ field :pending_price, type: :float
146
184
 
147
185
  ## credit spread only
148
186
  def close_price
@@ -151,8 +189,8 @@ class Iro::Position
151
189
  return out.round(2)
152
190
  end
153
191
 
154
- ## place2 = credit-spread
155
- def place2_price
192
+ ## credit-spread
193
+ def open_price
156
194
  pos = self
157
195
  out = pos.inner.begin_price - pos.outer.begin_price
158
196
  return out.round(2)
@@ -182,6 +220,15 @@ class Iro::Position
182
220
  def net_amount_short_credit_call_spread
183
221
  return net_amount_long_credit_put_spread
184
222
  end
223
+ def net_amount_short_debit_put_spread
224
+ inner.end_price - inner.begin_price + outer.begin_price - outer.end_price
225
+ end
226
+ def net_amount_diag_long_call_spread
227
+ inner.begin_price - outer.begin_price + outer.end_price - inner.end_price + realized_gl
228
+ end
229
+ def net_amount_diag_short_put_spread
230
+ net_amount_diag_long_call_spread
231
+ end
185
232
 
186
233
  def max_gain # each
187
234
  strategy.send("max_gain_#{strategy.kind}", self)
@@ -208,6 +255,19 @@ class Iro::Position
208
255
  outer.sync
209
256
  end
210
257
 
258
+ def schwab_query
259
+ pos = self
260
+ case pos.intent
261
+ when Iro::Strategy::INTENT_OPEN
262
+ the_q = Tda::Order.credit_spread_q pos
263
+ when Iro::Strategy::INTENT_ROLL
264
+ the_q = Tda::Order.roll_credit_call_spread_q pos
265
+ else
266
+ throw "prp - #schwab_query undefined for position #{pos.inspect}"
267
+ end
268
+ return the_q
269
+ end
270
+
211
271
  def self.sync_all
212
272
  @positions = Iro::Position.where( :status.in => [ 'active', 'pending' ] )
213
273
  expiration_dates = @positions.map { |p| p.expires_on.to_s }.sort
@@ -215,7 +275,7 @@ class Iro::Position
215
275
 
216
276
  count = 1
217
277
  @positions.each do |pos|
218
- # puts! pos.to_s, 'pos TMP'
278
+ # puts! pos.id.to_s, '#sync_all.pos'
219
279
 
220
280
  quotes_h = Tda::Option.get_quotes_h({
221
281
  contractType: 'ALL',
@@ -224,12 +284,17 @@ class Iro::Position
224
284
  toDate: expiration_dates.last,
225
285
  })
226
286
 
227
- pos.inner.end_price = quotes_h[pos.expires_on.to_s][pos.put_call][pos.inner.strike][:price]
228
- pos.inner.end_delta = quotes_h[pos.expires_on.to_s][pos.put_call][pos.inner.strike][:delta]
287
+ pos.inner.end_price = quotes_h[pos.expires_on.to_date.to_s][pos.put_call][pos.inner.strike][:price]
288
+ pos.inner.end_delta = quotes_h[pos.expires_on.to_date.to_s][pos.put_call][pos.inner.strike][:delta]
229
289
  pos.inner.save ? print("#{count}^") : print("#{count}X")
230
- if [ Iro::Strategy::KIND_LONG_CREDIT_PUT_SPREAD, Iro::Strategy::KIND_SHORT_CREDIT_CALL_SPREAD ].include?( pos.strategy.kind )
231
- pos.outer.end_price = quotes_h[pos.expires_on.to_s][pos.put_call][pos.outer.strike][:price]
232
- pos.outer.end_delta = quotes_h[pos.expires_on.to_s][pos.put_call][pos.outer.strike][:delta]
290
+
291
+ # if [ Iro::Strategy::KIND_LONG_CREDIT_PUT_SPREAD,
292
+ # Iro::Strategy::KIND_SHORT_CREDIT_CALL_SPREAD,
293
+ # Iro::Strategy::KIND_DIAG_LONG_CALL_SPREAD,
294
+ # Iro::Strategy::KIND_DIAG_SHORT_PUT_SPREAD ].include?( pos.strategy.kind )
295
+ if pos.outer
296
+ pos.outer.end_price = quotes_h[pos.expires_on.to_date.to_s][pos.put_call][pos.outer.strike][:price]
297
+ pos.outer.end_delta = quotes_h[pos.expires_on.to_date.to_s][pos.put_call][pos.outer.strike][:delta]
233
298
  pos.outer.save ? print('^') : print('X')
234
299
  end
235
300
  count = count+1
@@ -274,6 +339,11 @@ class Iro::Position
274
339
  # puts! outs, 'outs'
275
340
  outs_bk = outs.dup
276
341
 
342
+ ## cleanup mid-increments
343
+ outs = outs.select do |out|
344
+ ( out[:strikePrice] - pos.inner.strike ) % strategy.stock.options_price_increment == 0
345
+ end
346
+
277
347
  outs = outs.select do |out|
278
348
  out[:bidSize] + out[:askSize] > 0
279
349
  end
@@ -319,15 +389,8 @@ class Iro::Position
319
389
 
320
390
  ## next_inner_delta
321
391
  outs = outs.select do |out|
322
- if 'CALL' == pos.put_call
323
- out_delta = out[:delta] rescue 1
324
- out_delta <= strategy.next_inner_delta
325
- elsif 'PUT' == pos.put_call
326
- out_delta = out[:delta] rescue 0
327
- out_delta <= strategy.next_inner_delta
328
- else
329
- raise 'zt5 - this cannot happen'
330
- end
392
+ out_delta = out[:delta].abs rescue 0
393
+ out_delta <= strategy.next_inner_delta
331
394
  end
332
395
  # puts! outs[0][:strikePrice], 'after calc next_inner_delta'
333
396
  # puts! outs, 'outs'
@@ -422,15 +485,17 @@ class Iro::Position
422
485
 
423
486
  def to_s
424
487
  out = "#{stock} (#{q}) #{expires_on.to_datetime.strftime('%b %d')} #{strategy.long_or_short} ["
425
- if Iro::Strategy::LONG == long_or_short
488
+ if Iro::Strategy::KIND_SHORT_DEBIT_PUT_SPREAD == strategy.kind
489
+ out = out + "$#{outer.strike} << $#{inner.strike}"
490
+ elsif Iro::Strategy::LONG == long_or_short
426
491
  if outer&.strike
427
- out = out + "$#{outer.strike} <- "
492
+ out = out + "$#{outer.strike} << "
428
493
  end
429
494
  out = out + "$#{inner.strike}"
430
495
  else
431
496
  out = out + "$#{inner.strike}"
432
497
  if outer&.strike
433
- out = out + " -> $#{outer.strike}"
498
+ out = out + " >> $#{outer.strike}"
434
499
  end
435
500
  end
436
501
  out += "] "
@@ -24,8 +24,7 @@ class Iro::Purse
24
24
  ## with unit 100, .0001
25
25
  field :summary_unit, type: :float, default: 0.001
26
26
 
27
- ## for rolling only:
28
- field :height, type: :integer, default: 100
27
+ field :height, type: :integer, default: 100 ## px/q, units modal
29
28
 
30
29
  field :mark_every_n_usd, type: :float, default: 1
31
30
  field :n_next_positions, type: :integer, default: 5
@@ -32,6 +32,26 @@ class ::Iro::Stock
32
32
 
33
33
  field :descr, type: :string
34
34
 
35
+ ## for charting:
36
+ field :min, type: :integer
37
+ field :max, type: :integer
38
+ field :step, type: :integer, default: 1.0 ## for histograms. I liked 50 bars, that's $1-3 bucket size.
39
+
40
+ validate :step_must_fit_range
41
+ def step_must_fit_range
42
+ return if min.blank? || max.blank? || step.blank?
43
+
44
+ range = max. - min.to_i
45
+ step_val = step.to_i
46
+
47
+
48
+ if !((max - min) % step).zero?
49
+ errors.add(:step, "must evenly divide (max-min)/step")
50
+ end
51
+ end
52
+
53
+
54
+
35
55
  has_many :positions, class_name: '::Iro::Position', inverse_of: :stock
36
56
  has_many :strategies, class_name: '::Iro::Strategy', inverse_of: :stock
37
57
  # has_many :purses, class_name: '::Iro::Purse', inverse_of: :stock
@@ -24,6 +24,8 @@ class Iro::Strategy
24
24
  belongs_to :purse, class_name: 'Iro::Purse', inverse_of: :strategies
25
25
 
26
26
  KIND_COVERED_CALL = 'covered_call'
27
+ KIND_DIAG_LONG_CALL_SPREAD = 'diag_long_call_spread'
28
+ KIND_DIAG_SHORT_PUT_SPREAD = 'diag_short_put_spread'
27
29
  KIND_IRON_CONDOR = 'iron_condor'
28
30
  KIND_LONG_CREDIT_PUT_SPREAD = 'long_credit_put_spread'
29
31
  KIND_LONG_DEBIT_CALL_SPREAD = 'long_debit_call_spread'
@@ -36,6 +38,8 @@ class Iro::Strategy
36
38
  KIND_WHEEL = 'wheel' ## @deprecated, use covered_call
37
39
  KINDS = [ nil,
38
40
  KIND_COVERED_CALL,
41
+ KIND_DIAG_LONG_CALL_SPREAD,
42
+ KIND_DIAG_SHORT_PUT_SPREAD,
39
43
  KIND_IRON_CONDOR,
40
44
  KIND_LONG_CREDIT_PUT_SPREAD,
41
45
  KIND_LONG_DEBIT_CALL_SPREAD,
@@ -49,6 +53,12 @@ class Iro::Strategy
49
53
 
50
54
  def put_call
51
55
  case kind
56
+ when Iro::Strategy::KIND_COVERED_CALL
57
+ put_call = 'CALL'
58
+ when Iro::Strategy::KIND_DIAG_LONG_CALL_SPREAD
59
+ put_call = 'CALL'
60
+ when Iro::Strategy::KIND_DIAG_SHORT_PUT_SPREAD
61
+ put_call = 'PUT'
52
62
  when Iro::Strategy::KIND_LONG_CREDIT_PUT_SPREAD
53
63
  put_call = 'PUT'
54
64
  when Iro::Strategy::KIND_LONG_DEBIT_CALL_SPREAD
@@ -57,8 +67,7 @@ class Iro::Strategy
57
67
  put_call = 'CALL'
58
68
  when Iro::Strategy::KIND_SHORT_DEBIT_PUT_SPREAD
59
69
  put_call = 'PUT'
60
- when Iro::Strategy::KIND_COVERED_CALL
61
- put_call = 'CALL'
70
+
62
71
  when Iro::Strategy::KIND_SPREAD
63
72
  if credit_or_debit == CREDIT
64
73
  if long_or_short == LONG
@@ -77,11 +86,11 @@ class Iro::Strategy
77
86
  end
78
87
 
79
88
 
80
- field :threshold_usd_above_mark, type: :float
89
+ field :threshold_usd_above_mark, type: :float, default: 1.00
81
90
  validates :threshold_usd_above_mark, presence: true
82
91
 
83
92
  field :threshold_pos_delta, type: :float # offensive: roll b/c markets are going my way
84
- field :threshold_neg_delta, type: :float # defensive: roll b/c markets are going against me
93
+ field :threshold_neg_delta, type: :float, default: 0.8 # defensive: roll b/c markets are going against me
85
94
  field :threshold_netp, type: :float
86
95
  field :threshold_dte, type: :integer, default: 1
87
96
 
@@ -91,7 +100,7 @@ class Iro::Strategy
91
100
  field :next_outer_strike, type: :float
92
101
  field :next_spread_amount, type: :float # e.g. $20 for a $2000 NVDA spread
93
102
 
94
- field :next_usd_above_mark, type: :float
103
+ field :next_usd_above_mark, type: :float, default: 1.00
95
104
  validates :next_usd_above_mark, presence: true
96
105
 
97
106
 
@@ -108,12 +117,12 @@ class Iro::Strategy
108
117
  field :tgt_exposure, type: :float
109
118
 
110
119
 
120
+ def begin_delta p
121
+ _begin_delta_spread p
122
+ end
111
123
  def begin_delta_covered_call p
112
124
  p.inner.begin_delta
113
125
  end
114
- # def begin_delta_wheel p
115
- # p.inner.begin_delta
116
- # end
117
126
  def _begin_delta_spread p
118
127
  p.inner.begin_delta - p.outer.begin_delta
119
128
  end
@@ -123,13 +132,19 @@ class Iro::Strategy
123
132
  def begin_delta_short_credit_call_spread p
124
133
  _begin_delta_spread p
125
134
  end
135
+ def begin_delta_diag_long_call_spread p
136
+ _begin_delta_spread p
137
+ end
138
+ def begin_delta_diag_short_put_spread p
139
+ _begin_delta_spread p
140
+ end
126
141
 
142
+ def end_delta p
143
+ _end_delta_spread p
144
+ end
127
145
  def end_delta_covered_call p
128
146
  p.inner.end_delta
129
147
  end
130
- # def end_delta_wheel p
131
- # p.inner.end_delta
132
- # end
133
148
  def _end_delta_spread p
134
149
  p.inner.end_delta - p.outer.end_delta
135
150
  end
@@ -139,7 +154,21 @@ class Iro::Strategy
139
154
  def end_delta_short_credit_call_spread p
140
155
  _end_delta_spread p
141
156
  end
157
+ def end_delta_diag_long_call_spread p
158
+ _end_delta_spread p
159
+ end
160
+ def end_delta_diag_short_put_spread p
161
+ _end_delta_spread p
162
+ end
163
+
142
164
 
165
+ def max_gain_diag_long_call_spread p ## each
166
+ # p.outer.strike - p.inner.strike + p.outer.begin_price - p.inner.begin_price
167
+ p.inner.strike - p.outer.strike - p.outer.begin_price + p.inner.begin_price
168
+ end
169
+ def max_gain_diag_short_put_spread p ## each
170
+ p.outer.strike - p.inner.strike - p.outer.begin_price + p.inner.begin_price
171
+ end
143
172
 
144
173
  def max_gain_covered_call p ## each
145
174
  p.inner.begin_price # - 0.66
@@ -168,21 +197,31 @@ class Iro::Strategy
168
197
  end
169
198
 
170
199
 
200
+ def max_loss_diag_long_call_spread p
201
+ # p.inner.strike - p.outer.strike + p.inner.begin_price + p.outer.begin_price
202
+ p.outer.begin_price - p.inner.begin_price - p.realized_gl
203
+ end
204
+ def max_loss_diag_short_put_spread p
205
+ p.outer.begin_price - p.inner.begin_price - p.realized_gl ## same as above, max_loss_diag_long_call_spread
206
+ end
171
207
  def max_loss_covered_call p
172
208
  p.inner.begin_price*10 # just suppose 10,000%
173
209
  end
174
210
  def max_loss_long_credit_put_spread p
175
211
  out = p.inner.strike - p.outer.strike
176
212
  end
177
- def max_loss_long_debit_call_spread p
178
- out = p.outer.strike - p.inner.strike
179
- end
180
- def max_loss_short_debit_put_spread p # different
181
- out = p.inner.strike - p.outer.strike
182
- end
213
+ # def max_loss_long_debit_call_spread p
214
+ # out = p.outer.strike - p.inner.strike
215
+ # end
216
+ # def max_loss_short_debit_put_spread p # different
217
+ # out = p.inner.strike - p.outer.strike
218
+ # end
183
219
  def max_loss_short_credit_call_spread p
184
220
  out = p.outer.strike - p.inner.strike
185
221
  end
222
+ def max_loss_short_debit_put_spread p
223
+ p.inner.begin_price - p.outer.begin_price
224
+ end
186
225
  def max_loss_spread p
187
226
  ( p.outer.strike - p.inner.strike ).abs
188
227
  end
@@ -193,26 +232,9 @@ class Iro::Strategy
193
232
 
194
233
 
195
234
  def net_amount_spread p
196
- p.inner.begin_price - p.inner.end_price
235
+ p.inner.begin_price - p.inner.end_price - p.outer.begin_price + p.outer.end_price
197
236
  end
198
- # def net_amount_long_credit_put_spread p
199
- # p.inner.begin_price - p.inner.end_price
200
- # end
201
-
202
237
 
203
- ## 2024-05-09 _TODO
204
- ## 2025-10-11 _TODO
205
- ## 2026-02-23 trash, makes no sense.
206
- =begin
207
- def next_inner_strike_on expires_on
208
- outs = ::Tda::Option.get_quotes({
209
- contractType: put_call,
210
- expirationDate: expires_on,
211
- ticker: stock.ticker,
212
- })
213
- puts! outs, 'next_inner_strike_on -> outs'
214
- end
215
- =end
216
238
 
217
239
 
218
240
  ##
@@ -277,11 +299,6 @@ class Iro::Strategy
277
299
  def calc_rollp_long_credit_put_spread p
278
300
  stock.reload
279
301
 
280
- # puts! p, '#calc_rollp_long_credit_put_spread'
281
- # puts! p.inner, 'p.inner'
282
- # puts! stock, 'stock'
283
- # puts! attributes, 'strategy attributes'
284
-
285
302
  if ( p.expires_on.to_date - Time.now.to_date ).to_i < 1
286
303
  return [ 0.99, '0 DTE, must exit' ]
287
304
  end
@@ -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 params ...'
182
182
 
183
183
  profile = Wco::Profile.find_by email: 'piousbox@gmail.com'
184
184
  opts = {}
@@ -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.place2_price > 0 ? "NET_CREDIT" : "NET_DEBIT",
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.roll_price > 0 ? "NET_CREDIT" : "NET_DEBIT",
193
+ orderType: pos.pending_price > 0 ? "NET_CREDIT" : "NET_DEBIT",
194
194
  session: "NORMAL",
195
195
  duration: "DAY",
196
- price: pos.roll_price.abs.to_s,
196
+ price: pos.pending_price.abs.to_s,
197
197
  orderStrategyType: "SINGLE",
198
198
  orderLegCollection: [
199
199
  ## close
@@ -28,11 +28,6 @@ class Wco::Lead
28
28
  field :memory, type: Hash, default: {}
29
29
 
30
30
  belongs_to :leadset, class_name: 'Wco::Leadset'
31
- before_validation :set_leadset, on: :create
32
- def set_leadset
33
- domain = email.split('@')[1]
34
- self.leadset ||= Wco::Leadset.find_or_create_by({ company_url: domain })
35
- end
36
31
  before_validation :normalize_email, on: :create
37
32
  def normalize_email
38
33
  self[:email] = email.downcase
@@ -49,6 +44,12 @@ class Wco::Lead
49
44
  end
50
45
  return a
51
46
  end
47
+ before_validation :set_leadset, on: :create
48
+ def set_leadset
49
+ domain = email.split('@')[1]
50
+ self.leadset ||= Wco::Leadset.find_or_create_by({ company_url: domain })
51
+ end
52
+
52
53
  def self.find_or_create_by_email email
53
54
  email = self.normalize_email email
54
55
  out = where( email: email ).first
@@ -92,12 +92,17 @@ class Wco::Newspartial
92
92
  return out
93
93
  end
94
94
 
95
+ ##
96
+ ## Can I make do without puppet driver? Probably not: I need the audio worklet.
97
+ ##
95
98
  def generate_video
96
99
  cmd = "cd #{ISHLIB3JS_ROOT} ;
97
100
  node ./src/talking_head/example_puppeteer_wired.js \
98
- --api_key=#{SIMPLE_API_KEY} \
99
- --api_secret=#{SIMPLE_API_SECRET} \
101
+ --api_key=#{WCO_SIMPLE_API_KEY} \
102
+ --api_secret=#{WCO_SIMPLE_API_SECRET} \
100
103
  --wco_origin=#{WCO_ORIGIN} \
104
+ --w_px=#{newsvideo.w_px} \
105
+ --h_px=#{newsvideo.h_px} \
101
106
  --newspartial_id=#{self[:id]} ";
102
107
 
103
108
  puts "+++ cmd:"
@@ -26,6 +26,8 @@ class Wco::Newsvideo
26
26
  field :config_json, type: :string
27
27
  field :duration_ms, type: :integer
28
28
 
29
+ field :w_px, type: Integer
30
+ field :h_px, type: Integer
29
31
  field :x, :type => Float
30
32
  field :y, :type => Float
31
33
  field :z, :type => Float
@@ -15,6 +15,8 @@ class Wco::Photo
15
15
  belongs_to :gallery, class_name: 'Wco::Gallery', optional: true
16
16
  belongs_to :lead, class_name: 'Wco::Lead', optional: true
17
17
 
18
+ belongs_to :report, class_name: 'Wco::Report', optional: true
19
+
18
20
  has_many :email_templates, class_name: 'WcoEmail::EmailTemplate'
19
21
  # belongs_to :newsitem, :optional => true
20
22
 
@@ -10,6 +10,7 @@ class Wco::Profile
10
10
  validates :email, presence: true, uniqueness: true
11
11
 
12
12
  field :name
13
+ field :descr
13
14
 
14
15
 
15
16
  field :per_page, type: :integer, default: 25
@@ -31,10 +32,15 @@ class Wco::Profile
31
32
  field :smtp_password
32
33
  field :smtp_port
33
34
 
35
+ field :linkedin_client_id
36
+ field :linkedin_client_secret
37
+ field :linkedin_access_token
38
+
34
39
 
35
40
  has_many :newsvideos, class_name: 'Wco::Newsvideo'
36
41
  has_many :reports, class_name: 'Wco::Report'
37
42
  has_many :stocks, class_name: 'Iro::Stock'
43
+ has_many :sidebar_tags, class_name: 'Wco::Tag', inverse_of: :sidebar_profile
38
44
 
39
45
  belongs_to :leadset, class_name: 'Wco::Leadset', inverse_of: :profile
40
46
  has_many :newsitems, class_name: 'Wco::Newsitem'
@@ -28,13 +28,13 @@ class Wco::Publisher
28
28
  @headers = {}
29
29
  @ctx = OpenStruct.new
30
30
 
31
- puts! context_eval, 'context_eval'
31
+ # puts! context_eval, 'context_eval'
32
32
  eval( context_eval )
33
- puts! @ctx, '@ctx'
33
+ # puts! @ctx, '@ctx'
34
34
 
35
35
  tmpl = ERB.new post_body_tmpl
36
36
  body = JSON.parse tmpl.result(binding)
37
- puts! body, 'body'
37
+ # puts! body, 'body'
38
38
 
39
39
  out = Wco::HTTParty.post( "#{@site.origin}#{post_path}", {
40
40
  body: body.to_json,
@@ -13,7 +13,7 @@ class Wco::Report
13
13
 
14
14
  field :title
15
15
  validates :title, presence: true # , uniqueness: true
16
- index({ title: 1 }, { unique: true })
16
+ index({ title: 1 })
17
17
  def name ; title ; end
18
18
 
19
19
  field :subtitle
@@ -25,6 +25,9 @@ class Wco::Report
25
25
  before_validation :set_slug, on: :create
26
26
 
27
27
  field :body
28
+ def body_json
29
+ body.gsub(/\r/, '').gsub(/\n\n+/, '<br /><br />').to_json
30
+ end
28
31
 
29
32
  field :x, :type => Float
30
33
  field :y, :type => Float
@@ -32,8 +35,8 @@ class Wco::Report
32
35
 
33
36
  belongs_to :author, class_name: 'Wco::Profile'
34
37
 
35
- # has_one :image_thumb
36
- # has_one :image_hero
38
+ has_one :image_thumb, class_name: 'Wco::Photo', inverse_of: :report, dependent: :destroy
39
+ accepts_nested_attributes_for :image_thumb
37
40
 
38
41
  has_and_belongs_to_many :tags
39
42
 
@@ -25,7 +25,7 @@ class Wco::Site
25
25
  validates :slug, presence: true, uniqueness: true
26
26
 
27
27
  field :origin # http://pi.local
28
- validates :origin, presence: true, uniqueness: true
28
+ # validates :origin, presence: true, uniqueness: true
29
29
 
30
30
  field :post_path # /node?_format=hal_json
31
31
  field :username
@@ -39,7 +39,7 @@ class Wco::Site
39
39
  end
40
40
 
41
41
  def self.list
42
- [[nil,nil]] + all.map { |s| [ s.origin, s.id ] }
42
+ [[nil,nil]] + all.map { |s| [ s.slug, s.id ] }
43
43
  end
44
44
 
45
45
  def body
@@ -9,10 +9,13 @@ class Wco::Tag
9
9
  validates :slug, presence: true, uniqueness: true
10
10
  index({ slug: -1 })
11
11
 
12
+ field :weight, type: :string, default: 'jjj'
13
+
12
14
  belongs_to :parent, class_name: '::Wco::Tag', inverse_of: :sons, optional: true
13
15
  has_many :sons, class_name: '::Wco::Tag', inverse_of: :parent
14
16
 
15
17
  belongs_to :site, class_name: '::Wco::Site', optional: true
18
+ belongs_to :sidebar_profile, class_name: 'Wco::Profile', optional: true
16
19
  has_many :email_filters, class_name: '::WcoEmail::EmailFilter', inverse_of: :tag
17
20
  has_many :email_templates, class_name: '::WcoEmail::EmailTemplate', inverse_of: :tag
18
21
  has_many :ajects, class_name: '::WcoEmail::EmailFilterAction', inverse_of: :aject