iron_warbler 2.0.7.25 → 2.0.7.27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/iron_warbler/Card.scss +6 -0
  3. data/app/assets/stylesheets/iron_warbler/positions.scss +1 -1
  4. data/app/assets/stylesheets/iron_warbler/purses.scss +31 -0
  5. data/app/assets/stylesheets/iron_warbler/purses_summary.scss +31 -19
  6. data/app/assets/stylesheets/iron_warbler/utils.scss +28 -3
  7. data/app/controllers/iro/api/stocks_controller.rb +7 -4
  8. data/app/controllers/iro/application_controller.rb +6 -0
  9. data/app/controllers/iro/positions_controller.rb +188 -199
  10. data/app/controllers/iro/purses_controller.rb +3 -1
  11. data/app/controllers/iro/stocks_controller.rb +21 -2
  12. data/app/models/iro/datapoint.rb +1 -1
  13. data/app/models/iro/option.rb +50 -150
  14. data/app/models/iro/option_black_scholes.rb +149 -0
  15. data/app/models/iro/position.rb +155 -212
  16. data/app/models/iro/{price_item.rb → priceitem.rb} +5 -1
  17. data/app/models/iro/purse.rb +41 -4
  18. data/app/models/iro/stock.rb +2 -0
  19. data/app/models/iro/strategy.rb +121 -82
  20. data/app/models/tda/option.rb +1 -1
  21. data/app/models/tda/stock.rb +1 -1
  22. data/app/views/iro/_main_header.haml +8 -5
  23. data/app/views/iro/api/stocks/index.json.jbuilder +5 -0
  24. data/app/views/iro/api/stocks/show.json.jbuilder +11 -0
  25. data/app/views/iro/api/stocks/show.json.jbuilder-bk +12 -0
  26. data/app/views/iro/options/_show_mini.haml +8 -0
  27. data/app/views/iro/positions/_form.haml +11 -4
  28. data/app/views/iro/positions/_formpart_4data.haml +41 -38
  29. data/app/views/iro/positions/_gameui_long_debit_call_spread.haml +4 -4
  30. data/app/views/iro/positions/_gameui_long_debit_call_spread.haml-trash +42 -0
  31. data/app/views/iro/positions/_gameui_short_credit_call_spread.haml +38 -0
  32. data/app/views/iro/positions/_gameui_short_debit_put_spread.haml +1 -0
  33. data/app/views/iro/positions/_gameui_short_debit_put_spread.haml-trash +40 -0
  34. data/app/views/iro/positions/_header.haml +2 -0
  35. data/app/views/iro/positions/_header_long_debit_call_spread.haml +43 -25
  36. data/app/views/iro/positions/_header_short_credit_call_spread.haml +50 -0
  37. data/app/views/iro/positions/_new.haml +23 -0
  38. data/app/views/iro/positions/_prepare_long_debit_call_spread.haml +2 -3
  39. data/app/views/iro/positions/_prepare_short_credit_call_spread.haml +1 -0
  40. data/app/views/iro/positions/_prepare_short_debit_put_spread.haml +2 -1
  41. data/app/views/iro/positions/_table.haml +25 -26
  42. data/app/views/iro/positions/prepare.haml +6 -4
  43. data/app/views/iro/positions/prepare2.haml +15 -4
  44. data/app/views/iro/purses/_form_extra_fields.haml +18 -18
  45. data/app/views/iro/purses/_header.haml +12 -7
  46. data/app/views/iro/purses/_summary.haml +69 -62
  47. data/app/views/iro/purses/show.haml +4 -3
  48. data/app/views/iro/stocks/_form.haml +4 -3
  49. data/app/views/iro/stocks/edit.haml +4 -0
  50. data/app/views/iro/stocks/index.haml +21 -6
  51. data/app/views/iro/strategies/_form.haml +36 -26
  52. data/app/views/iro/strategies/_show.haml +7 -5
  53. data/config/routes.rb +7 -4
  54. data/lib/iro/engine.rb +1 -0
  55. data/lib/iron_warbler.rb +0 -2
  56. data/lib/tasks/iro_tasks.rake +2 -2
  57. metadata +17 -4
  58. data/app/views/iro/api/stocks/show.jbuilder +0 -11
  59. data/app/views/iro/positions/_gameui_short_debit_put_spread.haml +0 -40
@@ -5,11 +5,20 @@ class Iro::Position
5
5
  include Mongoid::Paranoia
6
6
  store_in collection: 'iro_positions'
7
7
 
8
+ field :prev_gain_loss_amount, type: :float
8
9
  attr_accessor :next_gain_loss_amount
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
+
9
15
 
10
16
  STATUS_ACTIVE = 'active'
17
+ STATUS_CLOSED = 'closed'
11
18
  STATUS_PROPOSED = 'proposed'
12
- STATUSES = [ nil, 'active', 'inactive', 'proposed' ]
19
+ ## one more, 'selected' after proposed?
20
+ STATUS_PENDING = 'pending' ## 'working'
21
+ STATUSES = [ nil, STATUS_CLOSED, STATUS_ACTIVE, STATUS_PROPOSED, STATUS_PENDING ]
13
22
  field :status
14
23
  validates :status, presence: true
15
24
  scope :active, ->{ where( status: 'active' ) }
@@ -17,27 +26,37 @@ class Iro::Position
17
26
  belongs_to :purse, class_name: 'Iro::Purse', inverse_of: :positions
18
27
  index({ purse_id: 1, ticker: 1 })
19
28
 
20
- belongs_to :prev, class_name: 'Iro::Position', inverse_of: :nxt
21
- has_one :nxt, class_name: 'Iro::Position', inverse_of: :prev
22
-
23
29
  belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :positions
24
- def ticker
25
- stock&.ticker || '-'
26
- end
30
+ delegate :ticker, to: :stock
27
31
 
28
32
  belongs_to :strategy, class_name: 'Iro::Strategy', inverse_of: :positions
33
+ delegate :put_call, to: :strategy
34
+ delegate :long_or_short, to: :strategy
29
35
 
30
- # field :ticker
31
- # validates :ticker, presence: true
36
+ belongs_to :next_strategy, class_name: 'Iro::Strategy', inverse_of: :next_position, optional: true
37
+
38
+
39
+ belongs_to :prev, class_name: 'Iro::Position', inverse_of: :nxts, optional: true
40
+ belongs_to :autoprev, class_name: 'Iro::Position', inverse_of: :autonxt, optional: true
41
+ ## there are many of these, for viewing on the 'roll' view
42
+ has_many :nxts, class_name: 'Iro::Position', inverse_of: :prev
43
+ has_one :autonxt, class_name: 'Iro::Position', inverse_of: :autoprev
44
+
45
+ ## Options
32
46
 
33
- belongs_to :outer, class_name: 'Iro::Option', inverse_of: :outer
34
47
  belongs_to :inner, class_name: 'Iro::Option', inverse_of: :inner
48
+ validates_associated :inner
49
+
50
+ belongs_to :outer, class_name: 'Iro::Option', inverse_of: :outer
51
+ validates_associated :outer
52
+
53
+ accepts_nested_attributes_for :inner, :outer
35
54
 
36
55
  field :outer_strike, type: :float
37
56
  # validates :outer_strike, presence: true
38
57
 
39
58
  field :inner_strike, type: :float
40
- validates :inner_strike, presence: true
59
+ # validates :inner_strike, presence: true
41
60
 
42
61
  field :expires_on
43
62
  validates :expires_on, presence: true
@@ -47,18 +66,8 @@ class Iro::Position
47
66
  def q; quantity; end
48
67
 
49
68
  field :begin_on
50
- field :begin_outer_price, type: :float
51
- field :begin_outer_delta, type: :float
52
-
53
- field :begin_inner_price, type: :float
54
- field :begin_inner_delta, type: :float
55
69
 
56
70
  field :end_on
57
- field :end_outer_price, type: :float
58
- field :end_outer_delta, type: :float
59
-
60
- field :end_inner_price, type: :float
61
- field :end_inner_delta, type: :float
62
71
 
63
72
  def begin_delta
64
73
  strategy.send("begin_delta_#{strategy.kind}", self)
@@ -86,7 +95,7 @@ class Iro::Position
86
95
  end_delta: out[:delta],
87
96
  end_price: out[:last],
88
97
  })
89
- print '_'
98
+ print '^'
90
99
  end
91
100
 
92
101
  def net_percent
@@ -101,237 +110,171 @@ class Iro::Position
101
110
  def max_loss # each
102
111
  strategy.send("max_loss_#{strategy.kind}", self)
103
112
  end
104
- # def gain_loss_amount
105
- # strategy.send("gain_loss_amount_#{strategy.kind}", self)
106
- # end
107
-
108
-
109
- field :next_delta, type: :float
110
- field :next_outcome, type: :float
111
- field :next_symbol
112
- field :next_mark
113
- field :next_reasons, type: :array, default: []
114
- field :rollp, type: :float
115
113
 
116
114
 
117
- ## covered call
118
- # def sync
119
- # puts! [ inner_strike, expires_on, stock.ticker ], 'init sync'
120
- # out = Tda::Option.get_quote({
121
- # contractType: 'CALL',
122
- # strike: inner_strike,
123
- # expirationDate: expires_on,
124
- # ticker: stock.ticker,
125
- # })
126
- # puts! out, 'sync'
127
- # self.end_inner_price = ( out.bid + out.ask ) / 2
128
- # self.end_inner_delta = out.delta
129
- # end
130
-
131
- ## long call spread
132
- # def sync
133
- # # puts! [
134
- # # [ inner_strike, expires_on, stock.ticker ],
135
- # # [ outer_strike, expires_on, stock.ticker ],
136
- # # ], 'init sync inner, outer'
137
- # inner = Tda::Option.get_quote({
138
- # contractType: 'CALL',
139
- # strike: inner_strike,
140
- # expirationDate: expires_on,
141
- # ticker: stock.ticker,
142
- # })
143
- # outer = Tda::Option.get_quote({
144
- # contractType: 'CALL',
145
- # strike: outer_strike,
146
- # expirationDate: expires_on,
147
- # ticker: stock.ticker,
148
- # })
149
- # puts! [inner, outer], 'sync inner, outer'
150
- # self.end_outer_price = ( outer.bid + outer.ask ) / 2
151
- # self.end_outer_delta = outer.delta
152
-
153
- # self.end_inner_price = ( inner.bid + inner.ask ) / 2
154
- # self.end_inner_delta = inner.delta
155
- # end
156
-
157
115
  def sync
158
- put_call = Iro::Strategy::LONG == strategy.long_or_short ? 'CALL' : 'PUT'
159
- puts! [
160
- [ inner_strike, expires_on, stock.ticker ],
161
- [ outer_strike, expires_on, stock.ticker ],
162
- ], 'init sync inner, outer'
163
- inner = Tda::Option.get_quote({
164
- contractType: put_call,
165
- strike: inner_strike,
166
- expirationDate: expires_on,
167
- ticker: stock.ticker,
168
- })
169
- outer = Tda::Option.get_quote({
170
- contractType: put_call,
171
- strike: outer_strike,
172
- expirationDate: expires_on,
173
- ticker: stock.ticker,
174
- })
175
- puts! [inner, outer], 'sync inner, outer'
176
- self.end_outer_price = ( outer.bid + outer.ask ) / 2
177
- self.end_outer_delta = outer.delta
178
-
179
- self.end_inner_price = ( inner.bid + inner.ask ) / 2
180
- self.end_inner_delta = inner.delta
116
+ inner.sync
117
+ outer.sync
181
118
  end
182
- def sync_short_debit_put_spread
183
- puts! [
184
- [ inner_strike, expires_on, stock.ticker ],
185
- [ outer_strike, expires_on, stock.ticker ],
186
- ], 'init sync inner, outer'
187
- inner = Tda::Option.get_quote({
188
- contractType: 'PUT',
189
- strike: inner_strike,
190
- expirationDate: expires_on,
191
- ticker: stock.ticker,
192
- })
193
- outer = Tda::Option.get_quote({
194
- contractType: 'PUT',
195
- strike: outer_strike,
196
- expirationDate: expires_on,
197
- ticker: stock.ticker,
198
- })
199
- puts! [inner, outer], 'sync inner, outer'
200
- self.end_outer_price = ( outer.bid + outer.ask ) / 2
201
- self.end_outer_delta = outer.delta
202
119
 
203
- self.end_inner_price = ( inner.bid + inner.ask ) / 2
204
- self.end_inner_delta = inner.delta
205
- end
206
120
 
207
121
  ##
208
122
  ## decisions
209
123
  ##
210
124
 
125
+ field :next_reasons, type: :array, default: []
126
+ field :rollp, type: :float
127
+
128
+ ## should_roll?
211
129
  def calc_rollp
212
130
  self.next_reasons = []
213
- self.next_symbol = nil
214
- self.next_delta = nil
131
+ # self.next_symbol = nil
132
+ # self.next_delta = nil
215
133
 
216
134
  out = strategy.send( "calc_rollp_#{strategy.kind}", self )
217
135
 
218
136
  self.rollp = out[0]
219
137
  self.next_reasons.push out[1]
220
138
  save
221
-
222
- # update({
223
- # next_delta: next_position[:delta],
224
- # next_outcome: next_position[:mark] - end_price,
225
- # next_symbol: next_position[:symbol],
226
- # next_mark: next_position[:mark],
227
- # should_rollp: out,
228
- # # status: Iro::Position::STATE_PROPOSED,
229
- # })
230
139
  end
231
140
 
232
-
233
- ## expires_on = cc.expires_on ; nil
234
- def can_roll?
235
- ## only if less than 7 days left
236
- ( expires_on.to_date - Time.now.to_date ).to_i < 7
237
- end
238
-
239
- ## strike = cc.strike ; strategy = cc.strategy ; nil
240
- def near_below_water?
241
- strike < current_underlying_strike + strategy.buffer_above_water
242
- end
243
-
244
-
245
-
246
- ## 2023-03-18 _vp_ Continue.
247
- ## 2023-03-19 _vp_ Continue.
248
- ## 2023-08-05 _vp_ an Important method
249
- ##
250
- ## expires_on = cc.expires_on ; strategy = cc.strategy ; ticker = cc.ticker ; end_price = cc.end_price ; next_expires_on = cc.next_expires_on ; nil
251
- ##
252
- ## out.map { |p| [ p[:strikePrice], p[:delta] ] }
253
- ##
254
- def next_position
255
- return @next_position if @next_position
256
- return {} if ![ STATUS_ACTIVE, STATUS_PROPOSED ].include?( status )
141
+ ## @TODO: herehere 2024-05-09
142
+ def calc_nxt
143
+ pos = self
257
144
 
258
145
  ## 7 days ahead - not configurable so far
259
- out = Tda::Option.get_quotes({
260
- ticker: ticker,
146
+ outs = Tda::Option.get_quotes({
147
+ contractType: pos.put_call,
261
148
  expirationDate: next_expires_on,
262
- contractType: 'CALL',
149
+ ticker: ticker,
263
150
  })
151
+ outs_bk = outs.dup
264
152
 
265
- ## above_water
266
- if strategy.buffer_above_water.present?
267
- out = out.select do |i|
268
- i[:strikePrice] > current_underlying_strike + strategy.buffer_above_water
269
- end
270
- # next_reasons.push "buffer_above_water above #{current_underlying_strike + strategy.buffer_above_water}"
153
+ outs = outs.select do |out|
154
+ out[:bidSize] + out[:askSize] > 0
271
155
  end
272
156
 
273
- if near_below_water?
274
- msg = "Panic! climb at a loss. Skip the rest of the calculation."
275
- next_reasons.push msg
276
- ## @TODO: if not enough money in the purse, cannot roll? 2023-03-19
157
+ ## next_inner_strike
158
+ outs = outs.select do |out|
159
+ if Iro::Strategy::SHORT == pos.long_or_short
160
+ out[:strikePrice] >= strategy.next_inner_strike
161
+ elsif Iro::Strategy::LONG == pos.long_or_short
162
+ out[:strikePrice] <= strategy.next_inner_strike
163
+ else
164
+ raise 'zz3 - this cannot happen'
165
+ end
166
+ end
167
+ puts! outs[0][:strikePrice], 'after calc next_inner_strike'
168
+
169
+ ## next_buffer_above_water
170
+ outs = outs.select do |out|
171
+ if Iro::Strategy::SHORT == pos.long_or_short
172
+ out[:strikePrice] > strategy.next_buffer_above_water + strategy.stock.last
173
+ elsif Iro::Strategy::LONG == pos.long_or_short
174
+ out[:strikePrice] < strategy.stock.last - strategy.next_buffer_above_water
175
+ else
176
+ raise 'zz4 - this cannot happen'
177
+ end
178
+ end
179
+ puts! outs[0][:strikePrice], 'after calc next_buffer_above_water'
277
180
 
278
- # byebug
181
+ ## next_inner_delta
182
+ outs = outs.select do |out|
183
+ out_delta = out[:delta].abs rescue 0
184
+ out_delta >= strategy.next_inner_delta.abs
185
+ end
186
+ puts! outs[0][:strikePrice], 'after calc next_inner_delta'
279
187
 
280
- ## Take a small loss here.
281
- prev = nil
282
- out.each_with_index do |i, idx|
283
- next if idx == 0
284
- if i[:last] < end_price
285
- prev ||= i
286
- end
287
- end
288
- out = [ prev ]
188
+ inner = outs[0]
189
+ outs = outs.select do |out|
190
+ out[:strikePrice] >= inner[:strikePrice].to_f + strategy.next_spread_amount
191
+ end
192
+ outer = outs[0]
193
+
194
+ if inner && outer
195
+ o_attrs = {
196
+ expires_on: next_expires_on,
197
+ put_call: pos.put_call,
198
+ stock_id: pos.stock_id,
199
+ }
200
+ inner_ = Iro::Option.new(o_attrs.merge({
201
+ strike: inner[:strikePrice],
202
+ begin_price: ( inner[:bid] + inner[:ask] )/2,
203
+ begin_delta: inner[:delta],
204
+ end_price: ( inner[:bid] + inner[:ask] )/2,
205
+ end_delta: inner[:delta],
206
+ }))
207
+ outer_ = Iro::Option.new(o_attrs.merge({
208
+ strike: outer[:strikePrice],
209
+ begin_price: ( outer[:bid] + outer[:ask] )/2,
210
+ begin_delta: outer[:delta],
211
+ end_price: ( outer[:bid] + outer[:ask] )/2,
212
+ end_delta: outer[:delta],
213
+ }))
214
+ pos.autonxt ||= Iro::Position.new
215
+ pos.autonxt.update({
216
+ prev_gain_loss_amount: 'a',
217
+ status: 'proposed',
218
+ stock: strategy.stock,
219
+ inner: inner_,
220
+ outer: outer_,
221
+ inner_strike: inner_.strike,
222
+ outer_strike: outer_.strike,
223
+ begin_on: Time.now.to_date,
224
+ expires_on: next_expires_on,
225
+ purse: purse,
226
+ strategy: strategy,
227
+ quantity: 1,
228
+ autoprev: pos,
229
+ })
230
+
231
+ pos.autonxt.sync
232
+ pos.autonxt.save!
233
+ pos.save
234
+ return pos
289
235
 
290
236
  else
291
- ## Normal flow, making money.
292
- ## @TODO: test! _vp_ 2023-03-19
293
-
294
- ## next_min_strike
295
- if strategy.next_min_strike.present?
296
- out = out.select do |i|
297
- i[:strikePrice] >= strategy.next_min_strike
298
- end
299
- # next_reasons.push "next_min_strike above #{strategy.next_min_strike}"
300
- end
301
- # json_puts! out.map { |p| [p[:delta], p[:symbol]] }, 'next_min_strike'
302
-
303
- ## max_delta
304
- if strategy.next_max_delta.present?
305
- out = out.select do |i|
306
- i[:delta] = 0.0 if i[:delta] == "NaN"
307
- i[:delta] <= strategy.next_max_delta
308
- end
309
- # next_reasons.push "next_max_delta below #{strategy.next_max_delta}"
310
- end
311
- # json_puts! out.map { |p| [p[:delta], p[:symbol]] }, 'next_max_delta'
237
+ throw 'zmq - should not happen'
312
238
  end
313
-
314
- @next_position = out[0] || {}
315
239
  end
316
240
 
317
- ## @TODO: Test this. _vp_ 2023-04-01
241
+
242
+
243
+ ## ok
318
244
  def next_expires_on
319
- out = expires_on.to_time + 7.days
320
- while !out.friday?
321
- out = out + 1.day
322
- end
323
- while !out.workday?
324
- out = out - 1.day
245
+ out = expires_on.to_datetime.next_occurring(:monday).next_occurring(:friday)
246
+ if !out.workday?
247
+ out = Time.previous_business_day(out)
325
248
  end
326
249
  return out
327
250
  end
328
251
 
252
+ ## ok
253
+ def self.long
254
+ where( long_or_short: Iro::Strategy::LONG )
255
+ end
256
+
257
+ ## ok
258
+ def self.short
259
+ where( long_or_short: Iro::Strategy::SHORT )
260
+ end
261
+
329
262
  def to_s
330
- out = "#{stock} (#{q}) #{expires_on.to_datetime.strftime('%b %d')} #{strategy.kind_short} ["
331
- if outer_strike
332
- out = out + "$#{outer_strike}->"
263
+ out = "#{stock} (#{q}) #{expires_on.to_datetime.strftime('%b %d')} #{strategy.long_or_short} ["
264
+ if Iro::Strategy::LONG == long_or_short
265
+ if outer.strike
266
+ out = out + "$#{outer.strike}->"
267
+ end
268
+ out = out + "$#{inner.strike}"
269
+ else
270
+ out = out + "$#{inner.strike}"
271
+ if outer.strike
272
+ out = out + "<-$#{outer.strike}"
273
+ end
333
274
  end
334
- out = out + "$#{inner_strike}] "
275
+ out += "] "
335
276
  return out
336
277
  end
337
278
  end
279
+
280
+
@@ -1,5 +1,8 @@
1
1
 
2
- class Iro::PriceItem
2
+ ##
3
+ ## specifically Option or Stock priceitem?
4
+ ##
5
+ class Iro::Priceitem
3
6
  include Mongoid::Document
4
7
  include Mongoid::Timestamps
5
8
  store_in collection: 'iro_price_items'
@@ -8,6 +11,7 @@ class Iro::PriceItem
8
11
  field :putCall, type: String
9
12
  field :symbol, type: String
10
13
  field :ticker, type: String
14
+ # belongs_to :stock, inverse_of: :priceitems
11
15
 
12
16
  field :bid, type: Float
13
17
  field :bidSize, type: Integer
@@ -1,4 +1,7 @@
1
1
 
2
+ require 'distribution'
3
+ N = Distribution::Normal
4
+
2
5
  class Iro::Purse
3
6
  include Mongoid::Document
4
7
  include Mongoid::Timestamps
@@ -9,22 +12,56 @@ class Iro::Purse
9
12
  validates :slug, presence: true, uniqueness: true
10
13
  index({ slug: -1 }, { unique: true })
11
14
 
12
- has_many :positions, class_name: 'Iro::Position', inverse_of: :purse
15
+ has_many :positions, class_name: 'Iro::Position', inverse_of: :purse
16
+
17
+ has_and_belongs_to_many :strategies, class_name: 'Iro::Strategy', inverse_of: :purses
13
18
 
14
19
  belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :strategies
15
20
 
16
21
  field :unit, type: :integer, default: 10
22
+ ## with unit 10, .001
23
+ ## with unit 100, .0001
24
+ field :summary_unit, type: :float, default: 0.001
17
25
 
18
26
  ## for rolling only:
19
27
  field :height, type: :integer, default: 100
20
28
 
21
29
  field :mark_every_n_usd, type: :float, default: 1
22
30
  field :n_next_positions, type: :integer, default: 5
23
- ## with unit 10, sum_scale .001
24
- ## with unit 100, sum_scale .0001
25
- field :summary_scale, type: :float, default: 0.001
26
31
 
27
32
  field :available_amount, type: :float
33
+ def available
34
+ available_amount
35
+ end
36
+
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
28
65
 
29
66
  def to_s
30
67
  slug
@@ -28,7 +28,9 @@ class Iro::Stock
28
28
  has_many :strategies, class_name: 'Iro::Strategy', inverse_of: :stock
29
29
  has_many :purses, class_name: 'Iro::Purse', inverse_of: :stock
30
30
  has_many :options, class_name: 'Iro::Option', inverse_of: :stock
31
+ has_many :priceitems, inverse_of: :stock
31
32
 
33
+ ## my_find
32
34
  def self.f ticker
33
35
  self.find_by ticker: ticker
34
36
  end