Class: Iro::Strategy

Inherits:
Object
  • Object
show all
Includes:
Mongoid::Document, Mongoid::Paranoia, Mongoid::Timestamps
Defined in:
app/models/iro/strategy.rb

Constant Summary collapse

LONG =
'long'
SHORT =
'short'
CREDIT =
'credit'
DEBIT =
'debit'
KIND_COVERED_CALL =

has_and_belongs_to_many :purses, class_name: ‘Iro::Purse’, inverse_of: :strategies

'covered_call'
KIND_IRON_CONDOR =
'iron_condor'
KIND_LONG_CREDIT_PUT_SPREAD =
'long_credit_put_spread'
KIND_LONG_DEBIT_CALL_SPREAD =
'long_debit_call_spread'
KIND_SHORT_CREDIT_CALL_SPREAD =
'short_credit_call_spread'
KIND_SHORT_DEBIT_PUT_SPREAD =
'short_debit_put_spread'
KIND_UNINVESTABLE =
'uninvestable'
KIND_LONG_ONLY =
'long-only'
KIND_SPREAD =

these are too simple and deprecated:

'spread'
KIND_WHEEL =

@deprecated, be specific

'wheel'
KINDS =

@deprecated, use covered_call

[ nil,
  KIND_COVERED_CALL,
  KIND_IRON_CONDOR,
  KIND_LONG_CREDIT_PUT_SPREAD,
  KIND_LONG_DEBIT_CALL_SPREAD,
  KIND_SHORT_CREDIT_CALL_SPREAD,
  KIND_SHORT_DEBIT_PUT_SPREAD,
  KIND_UNINVESTABLE,
  KIND_LONG_ONLY,
]

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.for_ticker(ticker) ⇒ Object

scopes



356
357
358
# File 'app/models/iro/strategy.rb', line 356

def self.for_ticker ticker
  where( ticker: ticker )
end

.list(long_or_short = nil) ⇒ Object



367
368
369
370
# File 'app/models/iro/strategy.rb', line 367

def self.list long_or_short = nil
  these = long_or_short ? where( long_or_short: long_or_short ) : all
  [[nil,nil]] + these.map { |st| [ st, st.id ] }
end

Instance Method Details

#_begin_delta_spread(p) ⇒ Object

def begin_delta_wheel p

p.inner.begin_delta

end



105
106
107
# File 'app/models/iro/strategy.rb', line 105

def _begin_delta_spread p
  p.inner.begin_delta - p.outer.begin_delta
end

#_end_delta_spread(p) ⇒ Object

def end_delta_wheel p

p.inner.end_delta

end



121
122
123
# File 'app/models/iro/strategy.rb', line 121

def _end_delta_spread p
  p.inner.end_delta - p.outer.end_delta
end

#begin_delta_covered_call(p) ⇒ Object



99
100
101
# File 'app/models/iro/strategy.rb', line 99

def begin_delta_covered_call p
  p.inner.begin_delta
end

#begin_delta_long_credit_put_spread(p) ⇒ Object



108
109
110
# File 'app/models/iro/strategy.rb', line 108

def begin_delta_long_credit_put_spread p
  _begin_delta_spread p
end

#begin_delta_short_credit_call_spread(p) ⇒ Object



111
112
113
# File 'app/models/iro/strategy.rb', line 111

def begin_delta_short_credit_call_spread p
  _begin_delta_spread p
end

#buffer_above_waterObject



82
# File 'app/models/iro/strategy.rb', line 82

def buffer_above_water; threshold_usd_above_mark; end

#calc_rollp_covered_call(p) ⇒ Object

decisions



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'app/models/iro/strategy.rb', line 210

def calc_rollp_covered_call p
  stock.reload

  if ( p.expires_on.to_date - Time.now.to_date ).to_i < 1
    return [ 0.99, '0 DTE, must exit' ]
  end

  if ( stock.last - buffer_above_water ) < p.inner.strike
    return [ 0.98, "Last #{'%.2f' % stock.last} is " +
      "#{'%.2f' % [p.inner.strike + buffer_above_water - stock.last]} " +
      "below #{'%.2f' % [p.inner.strike + buffer_above_water]} water" ]
  end

  if p.inner.end_delta < threshold_pos_delta
    return [ 0.61, "Delta #{p.inner.end_delta} is lower than #{threshold_pos_delta} threshold." ]
  end

  if 1 - p.inner.end_price/p.inner.begin_price > threshold_netp
    return [ 0.51, "made enough #{'%.02f' % [(1.0 - p.inner.end_price/p.inner.begin_price )*100]}% profit." ]
  end

  return [ 0.33, '-' ]
end

#calc_rollp_long_credit_put_spread(p) ⇒ Object

2025-10-12 _TODO



263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'app/models/iro/strategy.rb', line 263

def calc_rollp_long_credit_put_spread p
  stock.reload

  # puts! p, '#calc_rollp_long_credit_put_spread'
  # puts! p.inner, 'p.inner'
  puts! stock, 'stock'
  puts! attributes, 'strategy attributes'

  if ( p.expires_on.to_date - Time.now.to_date ).to_i < 1
    return [ 0.99, '0 DTE, must exit' ]
  end
  if ( p.expires_on.to_date - Time.now.to_date ).to_i < 2
    return [ 0.99, '1 DTE, must exit' ]
  end

  if ( stock.last - buffer_above_water ) < p.inner.strike
    return [ 0.95, "Last #{'%.2f' % stock.last} is " +
        "#{'%.2f' % [stock.last - p.inner.strike - buffer_above_water]} " +
        "below #{'%.2f' % [p.inner.strike + buffer_above_water]} water" ]
  end

  if p.inner.end_delta < threshold_pos_delta
    return [ 0.79, "Delta #{p.inner.end_delta} is lower than #{threshold_pos_delta} threshold." ]
  end

  if 1 - p.inner.end_price/p.inner.begin_price > threshold_netp
    return [ 0.51, "made enough #{'%.02f' % [(1.0 - p.inner.end_price/p.inner.begin_price )*100]}% profit^" ]
  end

  return [ 0.33, '-' ]
end

#calc_rollp_long_debit_call_spread(p) ⇒ Object

_TODO



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'app/models/iro/strategy.rb', line 235

def calc_rollp_long_debit_call_spread p
  stock.reload

  if ( p.expires_on.to_date - Time.now.to_date ).to_i < 1
    return [ 0.99, '0 DTE, must exit' ]
  end
  if ( p.expires_on.to_date - Time.now.to_date ).to_i < 2
    return [ 0.99, '1 DTE, must exit' ]
  end

  if ( stock.last - buffer_above_water ) < p.inner.strike
    return [ 0.95, "Last #{'%.2f' % stock.last} is " +
        "#{'%.2f' % [stock.last - p.inner.strike - buffer_above_water]} " +
        "below #{'%.2f' % [p.inner.strike + buffer_above_water]} water" ]
  end

  if p.inner.end_delta < threshold_pos_delta
    return [ 0.79, "Delta #{p.inner.end_delta} is lower than #{threshold_pos_delta} threshold." ]
  end

  if 1 - p.inner.end_price/p.inner.begin_price > threshold_netp
    return [ 0.51, "made enough #{'%.02f' % [(1.0 - p.inner.end_price/p.inner.begin_price )*100]}% profit^" ]
  end

  return [ 0.33, '-' ]
end

#calc_rollp_short_credit_call_spread(p) ⇒ Object

2026-02-21 ok



321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'app/models/iro/strategy.rb', line 321

def calc_rollp_short_credit_call_spread p
  puts! p, 'calc_rollp_short_credit_call_spread...'
  stock.reload

  if ( p.expires_on.to_date - Time.now.to_date ).to_i <= threshold_dte
    return [ 0.99, "< #{threshold_dte}DTE, must exit" ]
  end

  if stock.last + buffer_above_water > p.inner.strike
    return [ 0.95, "Last #{'%.2f' % stock.last} is " +
        "#{'%.2f' % [stock.last + buffer_above_water - p.inner.strike]} " +
        "above #{'%.2f' % [p.inner.strike - buffer_above_water]} water" ]
  end

  ## defensive
  ## inner short call is negative delta, but I'll deal with absolutes anyway.
  if p.inner.end_delta.abs > threshold_neg_delta.abs
    return [ 0.88, "Delta #{p.inner.end_delta} is larger than #{threshold_neg_delta} defensive threshold." ]
  end

  ## offensive
  if p.inner.end_delta.abs < threshold_pos_delta.abs
    return [ 0.69, "Delta #{p.inner.end_delta} is lower than #{threshold_pos_delta} offensive threshold." ]
  end

  if p.net_percent > threshold_netp
    return [ 0.51, "made enough #{'%.0f' % [p.net_percent*100]}% > #{"%.2f" % [threshold_netp*100]}% profit," ]
  end

  return [ 0.33, '-' ]
end

#calc_rollp_short_debit_put_spread(p) ⇒ Object

_TODO



296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'app/models/iro/strategy.rb', line 296

def calc_rollp_short_debit_put_spread p
  stock.reload

  if ( p.expires_on.to_date - Time.now.to_date ).to_i <= threshold_dte
    return [ 0.99, "< #{threshold_dte}DTE, must exit" ]
  end

  if stock.last + buffer_above_water > p.inner.strike
    return [ 0.98, "Last #{'%.2f' % stock.last} is " +
        "#{'%.2f' % [stock.last + buffer_above_water - p.inner.strike]} " +
        "above #{'%.2f' % [p.inner.strike - buffer_above_water]} water" ]
  end

  if p.inner.end_delta.abs < threshold_pos_delta.abs
    return [ 0.79, "Delta #{p.inner.end_delta} is lower than #{threshold_pos_delta} threshold." ]
  end

  if p.net_percent > threshold_netp
    return [ 0.51, "made enough #{'%.0f' % [p.net_percent*100]}% > #{"%.2f" % [threshold_netp*100]}% profit," ]
  end

  return [ 0.33, '-' ]
end

#end_delta_covered_call(p) ⇒ Object



115
116
117
# File 'app/models/iro/strategy.rb', line 115

def end_delta_covered_call p
  p.inner.end_delta
end

#end_delta_long_credit_put_spread(p) ⇒ Object



124
125
126
# File 'app/models/iro/strategy.rb', line 124

def end_delta_long_credit_put_spread p
  _end_delta_spread p
end

#end_delta_short_credit_call_spread(p) ⇒ Object



127
128
129
# File 'app/models/iro/strategy.rb', line 127

def end_delta_short_credit_call_spread p
  _end_delta_spread p
end

#max_gain_covered_call(p) ⇒ Object

each



132
133
134
# File 'app/models/iro/strategy.rb', line 132

def max_gain_covered_call p ## each
  p.inner.begin_price # - 0.66
end

#max_gain_long_credit_put_spread(p) ⇒ Object



135
136
137
138
# File 'app/models/iro/strategy.rb', line 135

def max_gain_long_credit_put_spread p
  ## 100 * disallowed for gameui
  p.inner.begin_price - p.outer.begin_price
end

#max_gain_long_debit_call_spread(p) ⇒ Object



139
140
141
142
# File 'app/models/iro/strategy.rb', line 139

def max_gain_long_debit_call_spread p
  ## 100 * disallowed for gameui
  ( p.inner.strike - p.outer.strike - p.outer.begin_price + p.inner.begin_price ) # - 2*0.66
end

#max_gain_short_credit_call_spread(p) ⇒ Object



143
144
145
# File 'app/models/iro/strategy.rb', line 143

def max_gain_short_credit_call_spread p
  p.inner.begin_price - p.outer.begin_price
end

#max_gain_short_debit_put_spread(p) ⇒ Object



146
147
148
149
# File 'app/models/iro/strategy.rb', line 146

def max_gain_short_debit_put_spread p
  ## 100 * disallowed for gameui
  ( p.outer.strike - p.inner.strike - p.outer.begin_price + p.inner.begin_price ) # - 2*0.66
end

#max_gain_spread(p) ⇒ Object



150
151
152
153
# File 'app/models/iro/strategy.rb', line 150

def max_gain_spread p
  ## 100 * disallowed for gameui
  ( p.outer.strike - p.inner.strike ).abs - p.outer.begin_price + p.inner.begin_price # - 2*0.66
end

#max_gain_wheel(p) ⇒ Object



154
155
156
# File 'app/models/iro/strategy.rb', line 154

def max_gain_wheel p
  p.inner.begin_price * 100 - 0.66 # @TODO: is this *100 really?
end

#max_loss_covered_call(p) ⇒ Object



159
160
161
# File 'app/models/iro/strategy.rb', line 159

def max_loss_covered_call p
  p.inner.begin_price*10 # just suppose 10,000%
end

#max_loss_long_credit_put_spread(p) ⇒ Object



162
163
164
# File 'app/models/iro/strategy.rb', line 162

def max_loss_long_credit_put_spread p
  out = p.inner.strike - p.outer.strike
end

#max_loss_long_debit_call_spread(p) ⇒ Object



165
166
167
# File 'app/models/iro/strategy.rb', line 165

def max_loss_long_debit_call_spread p
  out = p.outer.strike - p.inner.strike
end

#max_loss_short_credit_call_spread(p) ⇒ Object



171
172
173
# File 'app/models/iro/strategy.rb', line 171

def max_loss_short_credit_call_spread p
  out = p.outer.strike - p.inner.strike
end

#max_loss_short_debit_put_spread(p) ⇒ Object

different



168
169
170
# File 'app/models/iro/strategy.rb', line 168

def max_loss_short_debit_put_spread p # different
  out = p.inner.strike - p.outer.strike
end

#max_loss_spread(p) ⇒ Object



174
175
176
# File 'app/models/iro/strategy.rb', line 174

def max_loss_spread p
  ( p.outer.strike - p.inner.strike ).abs
end

#max_loss_wheel(p) ⇒ Object



177
178
179
# File 'app/models/iro/strategy.rb', line 177

def max_loss_wheel p
  p.inner.begin_price*10 # just suppose 10,000%
end

#net_amount_spread(p) ⇒ Object



183
184
185
# File 'app/models/iro/strategy.rb', line 183

def net_amount_spread p
  p.inner.begin_price - p.inner.end_price
end

#next_buffer_above_waterObject



97
# File 'app/models/iro/strategy.rb', line 97

def next_buffer_above_water; next_threshold_usd_above_mark; end

#next_positionObject

_TODO: makes no sense…



22
# File 'app/models/iro/strategy.rb', line 22

has_one  :next_position, class_name: 'Iro::Position', inverse_of: :next_strategy

#put_callObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'app/models/iro/strategy.rb', line 50

def put_call
  case kind
  when Iro::Strategy::KIND_LONG_CREDIT_PUT_SPREAD
    put_call = 'PUT'
  when Iro::Strategy::KIND_LONG_DEBIT_CALL_SPREAD
    put_call = 'CALL'
  when Iro::Strategy::KIND_SHORT_CREDIT_CALL_SPREAD
    put_call = 'CALL'
  when Iro::Strategy::KIND_SHORT_DEBIT_PUT_SPREAD
    put_call = 'PUT'
  when Iro::Strategy::KIND_COVERED_CALL
    put_call = 'CALL'
  when Iro::Strategy::KIND_SPREAD
    if credit_or_debit == CREDIT
      if long_or_short == LONG
        'PUT'
      elsif long_or_short == SHORT
        'CALL'
      else
        throw 'zq5 - should never happen'
      end
    else
      throw 'zq6 - debit spreads are not implemented'
    end
  else
    throw 'zq9 - this should never happen'
  end
end

#to_sObject

def slug

"#{kind} #{stock}"

end



364
365
366
# File 'app/models/iro/strategy.rb', line 364

def to_s
  "#{kind} #{stock}"
end