iron_warbler 2.0.7.19 → 2.0.7.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascript/iron_warbler/application.js +2 -0
  3. data/app/assets/javascript/iron_warbler/gameui.js +9 -0
  4. data/app/assets/stylesheets/iron_warbler/application.css +13 -3
  5. data/app/assets/stylesheets/iron_warbler/positions.scss +9 -1
  6. data/app/assets/stylesheets/iron_warbler/purses_gameui.scss +191 -0
  7. data/app/assets/stylesheets/iron_warbler/purses_gameui.scss-bk +112 -0
  8. data/app/assets/stylesheets/iron_warbler/utils.scss +82 -0
  9. data/app/controllers/iro/api/stocks_controller.rb +87 -0
  10. data/app/controllers/iro/api_controller.rb +19 -0
  11. data/app/controllers/iro/positions_controller.rb +16 -4
  12. data/app/controllers/iro/purses_controller.rb +8 -3
  13. data/app/controllers/iro/strategies_controller.rb +7 -7
  14. data/app/helpers/iro/application_helper.rb +5 -2
  15. data/app/models/iro/datapoint.rb +48 -8
  16. data/app/models/iro/position.rb +55 -14
  17. data/app/models/iro/position_covered_call.rb +4 -0
  18. data/app/models/iro/position_debit_spread.rb +251 -0
  19. data/app/models/iro/price_item.rb +51 -1
  20. data/app/models/iro/stock.rb +5 -2
  21. data/app/models/iro/strategy.rb +76 -10
  22. data/app/views/iro/_main_header.haml +18 -17
  23. data/app/views/iro/api/stocks/show.jbuilder +11 -0
  24. data/app/views/iro/positions/_form.haml +11 -38
  25. data/app/views/iro/positions/_formpart_4data.haml +46 -0
  26. data/app/views/iro/positions/_gameui_covered_call.haml +36 -0
  27. data/app/views/iro/positions/_gameui_covered_call.haml-bk +59 -0
  28. data/app/views/iro/positions/_gameui_long_debit_call_spread.haml +37 -0
  29. data/app/views/iro/positions/_gameui_short_debit_put_spread.haml +39 -0
  30. data/app/views/iro/positions/_header.haml +6 -0
  31. data/app/views/iro/positions/_header_covered_call.haml +6 -0
  32. data/app/views/iro/positions/_header_long_debit_call_spread.haml +14 -0
  33. data/app/views/iro/positions/_header_short_debit_put_spread.haml +1 -0
  34. data/app/views/iro/positions/_table.haml +118 -123
  35. data/app/views/iro/positions/roll.haml +83 -0
  36. data/app/views/iro/positions/trash/_header_short_debit_put_spread.haml +9 -0
  37. data/app/views/iro/purses/_header.haml +18 -0
  38. data/app/views/iro/purses/gameui.haml +18 -0
  39. data/app/views/iro/purses/gameui.haml-bk +44 -0
  40. data/app/views/iro/purses/gameui.haml-bk2 +89 -0
  41. data/app/views/iro/purses/show.haml +1 -7
  42. data/app/views/iro/stocks/_grid_is_long.haml +13 -0
  43. data/app/views/iro/stocks/_grid_is_short.haml +13 -0
  44. data/app/views/iro/strategies/_form.haml +12 -5
  45. data/app/views/iro/strategies/_show.haml +3 -2
  46. data/app/views/iro/strategies/_table.haml +16 -10
  47. data/app/views/iro/strategies/index.haml +8 -0
  48. data/app/views/layouts/iro/application.haml +1 -1
  49. data/config/routes.rb +14 -1
  50. data/lib/tasks/db_tasks.rake +9 -3
  51. metadata +29 -8
  52. data/app/assets/stylesheets/iron_warbler/alerts.css +0 -8
  53. data/app/assets/stylesheets/iron_warbler/datapoints.css +0 -0
  54. data/app/assets/stylesheets/iron_warbler/profiles.css +0 -4
  55. data/app/assets/stylesheets/iron_warbler/strategies.scss +0 -0
  56. data/app/assets/stylesheets/iron_warbler/utils.css +0 -44
  57. data/app/jobs/iro/application_job.rb-trash +0 -4
@@ -5,15 +5,34 @@ class Iro::Datapoint
5
5
  include Mongoid::Timestamps
6
6
  store_in collection: 'iro_datapoints'
7
7
 
8
- field :date
8
+ field :kind ## PUT, CALL, STOCK, CURRENCY, CRYPTO
9
+ validates :kind, presence: true
10
+ index({ kind: -1 })
11
+
12
+ field :symbol ## ticker, but use 'symbol' ONLY
13
+
14
+ field :date, type: Date ## @obsolete, use quote_at
9
15
  index({ kind: -1, date: -1 })
10
16
 
17
+ field :quote_at, type: DateTime
18
+ index({ kind: -1, quote_at: -1 })
19
+ validates :quote_at, uniqueness: { scope: [ :kind, :symbol ] }
20
+
21
+ field :open, type: Float
22
+ field :high, type: Float
23
+ field :low, type: Float
24
+
11
25
  field :value, type: Float
12
26
  validates :value, presence: true
27
+ def close
28
+ value
29
+ end
30
+ def close= a
31
+ value= a
32
+ end
33
+
34
+ field :volume, type: Integer
13
35
 
14
- field :kind
15
- validates :kind, presence: true
16
- index({ kind: -1 })
17
36
 
18
37
  def self.test_0trash
19
38
  add_fields = { '$addFields': {
@@ -21,10 +40,10 @@ class Iro::Datapoint
21
40
  '$dateToString': { 'format': "%Y-%m-%d", 'date': "$created_at" }
22
41
  }
23
42
  } }
24
- group = { '$group': {
25
- '_id': "$date_string",
26
- 'my_doc': { '$first': "$$ROOT" }
27
- } }
43
+ # group = { '$group': {
44
+ # '_id': "$date_string",
45
+ # 'my_doc': { '$first': "$$ROOT" }
46
+ # } }
28
47
  group = { '$group': {
29
48
  '_id': "$date",
30
49
  'my_doc': { '$first': "$$ROOT" }
@@ -113,4 +132,25 @@ class Iro::Datapoint
113
132
  # puts! outs.to_a, 'result'
114
133
  end
115
134
 
135
+ def self.import_stock symbol:, path:
136
+ csv = CSV.read(path, headers: true)
137
+ csv.each do |row|
138
+ flag = create({
139
+ kind: 'STOCK',
140
+ symbol: symbol,
141
+ date: row['date'],
142
+ quote_at: row['date'],
143
+
144
+ volume: row['volume'],
145
+
146
+ open: row['open'],
147
+ high: row['high'],
148
+ low: row['low'],
149
+ value: row['close'],
150
+ })
151
+ print '.' if flag.persisted?
152
+ end
153
+ puts 'ok'
154
+ end
155
+
116
156
  end
@@ -4,6 +4,8 @@ class Iro::Position
4
4
  include Mongoid::Timestamps
5
5
  store_in collection: 'iro_positions'
6
6
 
7
+ attr_accessor :gain_loss_amount
8
+
7
9
  STATUS_ACTIVE = 'active'
8
10
  STATUS_PROPOSED = 'proposed'
9
11
  STATUSES = [ nil, 'active', 'inactive', 'proposed' ]
@@ -12,34 +14,48 @@ class Iro::Position
12
14
  scope :active, ->{ where( status: 'active' ) }
13
15
 
14
16
  belongs_to :purse, class_name: 'Iro::Purse', inverse_of: :positions
17
+ index({ purse_id: 1, ticker: 1 })
18
+
19
+ belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :positions
20
+ def ticker
21
+ stock&.ticker || '-'
22
+ end
23
+
15
24
  belongs_to :strategy, class_name: 'Iro::Strategy', inverse_of: :positions
16
25
 
17
- field :ticker
18
- validates :ticker, presence: true
19
- index({ purse_id: 1, ticker: 1 })
26
+ # field :ticker
27
+ # validates :ticker, presence: true
20
28
 
21
- KINDS = [ nil, 'covered_call', 'credit_put_spread', 'credit_call_spread' ]
22
- field :kind
29
+ field :outer_strike, type: :float
30
+ # validates :outer_strike, presence: true
23
31
 
24
- field :strike, type: :float
25
- validates :strike, presence: true
32
+ field :inner_strike, type: :float
33
+ validates :inner_strike, presence: true
26
34
 
27
35
  field :expires_on
28
36
  validates :expires_on, presence: true
29
37
 
30
38
  field :quantity, type: :integer
31
39
  validates :quantity, presence: true
40
+ def q; quantity; end
32
41
 
33
42
  field :begin_on
34
- field :begin_price, type: :float
35
- field :begin_delta, type: :float
43
+ field :begin_outer_price, type: :float
44
+ field :begin_outer_delta, type: :float
45
+
46
+ field :begin_inner_price, type: :float
47
+ field :begin_inner_delta, type: :float
36
48
 
37
49
  field :end_on
38
- field :end_price, type: :float
39
- field :end_delta, type: :float
50
+ field :end_outer_price, type: :float
51
+ field :end_outer_delta, type: :float
40
52
 
41
- field :net_amount
42
- field :net_percent
53
+ field :end_inner_price, type: :float
54
+ field :end_inner_delta, type: :float
55
+
56
+ def breakeven
57
+ inner_strike - begin_outer_price + begin_inner_price
58
+ end
43
59
 
44
60
  def current_underlying_strike
45
61
  Iro::Stock.find_by( ticker: ticker ).last
@@ -59,6 +75,19 @@ class Iro::Position
59
75
  print '_'
60
76
  end
61
77
 
78
+ def net_percent
79
+ net_amount / max_gain
80
+ end
81
+ def net_amount # each
82
+ strategy.send("net_amount_#{strategy.kind}", self)
83
+ end
84
+ def max_gain # each
85
+ strategy.send("max_gain_#{strategy.kind}", self)
86
+ end
87
+ def max_loss # each
88
+ strategy.send("max_loss_#{strategy.kind}", self)
89
+ end
90
+
62
91
 
63
92
  field :next_delta, type: :float
64
93
  field :next_outcome, type: :float
@@ -67,6 +96,10 @@ class Iro::Position
67
96
  field :next_reasons, type: :array, default: []
68
97
  field :should_rollp, type: :float
69
98
 
99
+ ##
100
+ ## decisions
101
+ ##
102
+
70
103
  def should_roll?
71
104
  puts! 'shold_roll?'
72
105
 
@@ -83,7 +116,7 @@ class Iro::Position
83
116
  if end_delta < strategy.threshold_delta
84
117
  next_reasons.push "delta is lower than threshold"
85
118
  out = 0.91
86
- elsif 1 - end_price/begin_price > strategy.threshold_netp
119
+ elsif 1 - end_outer_price/begin_outer_price > strategy.threshold_netp
87
120
  next_reasons.push "made enough percent profit (dubious)"
88
121
  out = 0.61
89
122
  else
@@ -219,4 +252,12 @@ class Iro::Position
219
252
  return out
220
253
  end
221
254
 
255
+ def to_s
256
+ out = "#{stock} (#{q}) #{expires_on.to_datetime.strftime('%b %d')} #{strategy.kind_short} ["
257
+ if outer_strike
258
+ out = out + "$#{outer_strike}->"
259
+ end
260
+ out = out + "$#{inner_strike}] "
261
+ return out
262
+ end
222
263
  end
@@ -0,0 +1,4 @@
1
+
2
+ class Iro::PositionCoveredCall < Iro::Position
3
+
4
+ end
@@ -0,0 +1,251 @@
1
+
2
+ class Iro::PositionDebitSpread < Iro::Positin
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ store_in collection: 'iro_positions'
6
+
7
+ STATUS_ACTIVE = 'active'
8
+ STATUS_PROPOSED = 'proposed'
9
+ STATUSES = [ nil, 'active', 'inactive', 'proposed' ]
10
+ field :status
11
+ validates :status, presence: true
12
+ scope :active, ->{ where( status: 'active' ) }
13
+
14
+ belongs_to :purse, class_name: 'Iro::Purse', inverse_of: :positions
15
+ index({ purse_id: 1, ticker: 1 })
16
+
17
+ belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :positions
18
+ def ticker
19
+ stock&.ticker || '-'
20
+ end
21
+
22
+ belongs_to :strategy, class_name: 'Iro::Strategy', inverse_of: :positions
23
+
24
+ field :outer_strike, type: :float
25
+ validates :outer_strike, presence: true
26
+
27
+ field :inner_strike, type: :float
28
+ validates :inner_strike, presence: true
29
+
30
+ field :expires_on
31
+ validates :expires_on, presence: true
32
+
33
+ field :quantity, type: :integer
34
+ validates :quantity, presence: true
35
+
36
+ field :begin_on
37
+ field :begin_outer_price, type: :float
38
+ field :begin_outer_delta, type: :float
39
+
40
+ field :begin_inner_price, type: :float
41
+ field :begin_inner_delta, type: :float
42
+
43
+ field :end_on
44
+ field :end_outer_price, type: :float
45
+ field :end_outer_delta, type: :float
46
+
47
+ field :end_inner_price, type: :float
48
+ field :end_inner_delta, type: :float
49
+
50
+ field :net_amount
51
+ field :net_percent
52
+
53
+ def current_underlying_strike
54
+ Iro::Stock.find_by( ticker: ticker ).last
55
+ end
56
+
57
+ def refresh
58
+ out = Tda::Option.get_quote({
59
+ contractType: 'CALL',
60
+ strike: strike,
61
+ expirationDate: expires_on,
62
+ ticker: ticker,
63
+ })
64
+ update({
65
+ end_delta: out[:delta],
66
+ end_price: out[:last],
67
+ })
68
+ print '_'
69
+ end
70
+
71
+ def net_amount # total
72
+ outer = 0 - begin_outer_price + end_outer_price
73
+ inner = begin_inner_price - end_inner_price
74
+ out = ( outer + inner ) * 100 * quantity
75
+ end
76
+ def max_gain # total
77
+ 100 * ( begin_outer_price - begin_inner_price ) * quantity
78
+ end
79
+ def max_loss
80
+ out = 100 * ( outer_strike - inner_strike ) * quantity
81
+ if strategy.long_or_short == Iro::Strategy::SHORT
82
+ out = out * -1
83
+ end
84
+ return out
85
+ end
86
+
87
+
88
+ field :next_delta, type: :float
89
+ field :next_outcome, type: :float
90
+ field :next_symbol
91
+ field :next_mark
92
+ field :next_reasons, type: :array, default: []
93
+ field :should_rollp, type: :float
94
+
95
+ ##
96
+ ## decisions
97
+ ##
98
+
99
+ def should_roll?
100
+ puts! 'shold_roll?'
101
+
102
+ update({
103
+ next_reasons: [],
104
+ next_symbol: nil,
105
+ next_delta: nil,
106
+ })
107
+
108
+ if must_roll?
109
+ out = 1.0
110
+ elsif can_roll?
111
+
112
+ if end_delta < strategy.threshold_delta
113
+ next_reasons.push "delta is lower than threshold"
114
+ out = 0.91
115
+ elsif 1 - end_outer_price/begin_outer_price > strategy.threshold_netp
116
+ next_reasons.push "made enough percent profit (dubious)"
117
+ out = 0.61
118
+ else
119
+ next_reasons.push "neutral"
120
+ out = 0.33
121
+ end
122
+
123
+ else
124
+ out = 0.0
125
+ end
126
+
127
+ update({
128
+ next_delta: next_position[:delta],
129
+ next_outcome: next_position[:mark] - end_price,
130
+ next_symbol: next_position[:symbol],
131
+ next_mark: next_position[:mark],
132
+ should_rollp: out,
133
+ # status: Iro::Position::STATE_PROPOSED,
134
+ })
135
+
136
+ puts! next_reasons, 'next_reasons'
137
+ puts! out, 'out'
138
+ return out > 0.5
139
+ end
140
+
141
+
142
+ ## expires_on = cc.expires_on ; nil
143
+ def can_roll?
144
+ ## only if less than 7 days left
145
+ ( expires_on.to_date - Time.now.to_date ).to_i < 7
146
+ end
147
+
148
+ ## If I'm near below water
149
+ ##
150
+ ## expires_on = cc.expires_on ; strategy = cc.strategy ; strike = cc.strike ; nil
151
+ def must_roll?
152
+ if ( current_underlying_strike + strategy.buffer_above_water ) > strike
153
+ return true
154
+ end
155
+ ## @TODO: This one should not happen, I should log appropriately. _vp_ 2023-03-19
156
+ if ( expires_on.to_date - Time.now.to_date ).to_i < 1
157
+ return true
158
+ end
159
+ end
160
+
161
+ ## strike = cc.strike ; strategy = cc.strategy ; nil
162
+ def near_below_water?
163
+ strike < current_underlying_strike + strategy.buffer_above_water
164
+ end
165
+
166
+
167
+
168
+ ## 2023-03-18 _vp_ Continue.
169
+ ## 2023-03-19 _vp_ Continue.
170
+ ## 2023-08-05 _vp_ an Important method
171
+ ##
172
+ ## expires_on = cc.expires_on ; strategy = cc.strategy ; ticker = cc.ticker ; end_price = cc.end_price ; next_expires_on = cc.next_expires_on ; nil
173
+ ##
174
+ ## out.map { |p| [ p[:strikePrice], p[:delta] ] }
175
+ ##
176
+ def next_position
177
+ return @next_position if @next_position
178
+ return {} if ![ STATUS_ACTIVE, STATUS_PROPOSED ].include?( status )
179
+
180
+ ## 7 days ahead - not configurable so far
181
+ out = Tda::Option.get_quotes({
182
+ ticker: ticker,
183
+ expirationDate: next_expires_on,
184
+ contractType: 'CALL',
185
+ })
186
+
187
+ ## above_water
188
+ if strategy.buffer_above_water.present?
189
+ out = out.select do |i|
190
+ i[:strikePrice] > current_underlying_strike + strategy.buffer_above_water
191
+ end
192
+ # next_reasons.push "buffer_above_water above #{current_underlying_strike + strategy.buffer_above_water}"
193
+ end
194
+
195
+ if near_below_water?
196
+ msg = "Panic! climb at a loss. Skip the rest of the calculation."
197
+ next_reasons.push msg
198
+ ## @TODO: if not enough money in the purse, cannot roll? 2023-03-19
199
+
200
+ # byebug
201
+
202
+ ## Take a small loss here.
203
+ prev = nil
204
+ out.each_with_index do |i, idx|
205
+ next if idx == 0
206
+ if i[:last] < end_price
207
+ prev ||= i
208
+ end
209
+ end
210
+ out = [ prev ]
211
+
212
+ else
213
+ ## Normal flow, making money.
214
+ ## @TODO: test! _vp_ 2023-03-19
215
+
216
+ ## next_min_strike
217
+ if strategy.next_min_strike.present?
218
+ out = out.select do |i|
219
+ i[:strikePrice] >= strategy.next_min_strike
220
+ end
221
+ # next_reasons.push "next_min_strike above #{strategy.next_min_strike}"
222
+ end
223
+ # json_puts! out.map { |p| [p[:delta], p[:symbol]] }, 'next_min_strike'
224
+
225
+ ## max_delta
226
+ if strategy.next_max_delta.present?
227
+ out = out.select do |i|
228
+ i[:delta] = 0.0 if i[:delta] == "NaN"
229
+ i[:delta] <= strategy.next_max_delta
230
+ end
231
+ # next_reasons.push "next_max_delta below #{strategy.next_max_delta}"
232
+ end
233
+ # json_puts! out.map { |p| [p[:delta], p[:symbol]] }, 'next_max_delta'
234
+ end
235
+
236
+ @next_position = out[0] || {}
237
+ end
238
+
239
+ ## @TODO: Test this. _vp_ 2023-04-01
240
+ def next_expires_on
241
+ out = expires_on.to_time + 7.days
242
+ while !out.friday?
243
+ out = out + 1.day
244
+ end
245
+ while !out.workday?
246
+ out = out - 1.day
247
+ end
248
+ return out
249
+ end
250
+
251
+ end
@@ -4,6 +4,7 @@ class Iro::PriceItem
4
4
  include Mongoid::Timestamps
5
5
  store_in collection: 'iro_price_items'
6
6
 
7
+ ## PUT, CALL, STOCK
7
8
  field :putCall, type: String
8
9
  field :symbol, type: String
9
10
  field :ticker, type: String
@@ -15,9 +16,9 @@ class Iro::PriceItem
15
16
  field :last, type: Float
16
17
 
17
18
  field :openPrice, type: Float
18
- field :closePrice, type: Float
19
19
  field :lowPrice, type: Float
20
20
  field :highPrice, type: Float
21
+ field :closePrice, type: Float
21
22
 
22
23
  field :quoteTimeInLong, type: Integer
23
24
  field :timestamp, type: Integer
@@ -26,4 +27,53 @@ class Iro::PriceItem
26
27
  field :exchangeName, type: String
27
28
  field :volatility, type: Float
28
29
 
30
+ def self.my_find props={}
31
+ lookup = { '$lookup': {
32
+ 'from': 'iro_price_items',
33
+ 'localField': 'date',
34
+ 'foreignField': 'date',
35
+ 'pipeline': [
36
+ { '$sort': { 'value': -1 } },
37
+ ],
38
+ 'as': 'dates',
39
+ } }
40
+ lookup_merge = { '$replaceRoot': {
41
+ 'newRoot': { '$mergeObjects': [
42
+ { '$arrayElemAt': [ "$dates", 0 ] }, "$$ROOT"
43
+ ] }
44
+ } }
45
+
46
+
47
+ match = { '$match': {
48
+ 'date': {
49
+ '$gte': props[:begin_on],
50
+ '$lte': props[:end_on],
51
+ }
52
+ } }
53
+
54
+ group = { '$group': {
55
+ '_id': "$date",
56
+ 'my_doc': { '$first': "$$ROOT" }
57
+ } }
58
+
59
+ outs = Iro::Date.collection.aggregate([
60
+ match,
61
+
62
+ lookup,
63
+ lookup_merge,
64
+
65
+ group,
66
+ { '$replaceRoot': { 'newRoot': "$my_doc" } },
67
+ # { '$replaceRoot': { 'newRoot': "$my_doc" } },
68
+
69
+
70
+ { '$project': { '_id': 0, 'date': 1, 'value': 1 } },
71
+ { '$sort': { 'date': 1 } },
72
+ ])
73
+
74
+ puts! 'result'
75
+ pp outs.to_a
76
+ # puts! outs.to_a, 'result'
77
+ end
78
+
29
79
  end
@@ -18,13 +18,16 @@ class Iro::Stock
18
18
 
19
19
  field :last, type: :float
20
20
 
21
-
22
- # has_many :strategies, class_name: 'Iro::Strategy', inverse_of: :stock
21
+ has_many :positions, class_name: 'Iro::Position', inverse_of: :stock
22
+ has_many :strategies, class_name: 'Iro::Strategy', inverse_of: :stock
23
23
 
24
24
  def to_s
25
25
  ticker
26
26
  end
27
27
  def self.list
28
+ [[nil,nil]] + all.map { |sss| [ sss.ticker, sss.id ] }
29
+ end
30
+ def self.tickers_list
28
31
  [[nil,nil]] + all.map { |sss| [ sss.ticker, sss.ticker ] }
29
32
  end
30
33
  end
@@ -7,17 +7,43 @@ class Iro::Strategy
7
7
  field :slug
8
8
  validates :slug, presence: true, uniqueness: true
9
9
 
10
+ LONG = 'is_long'
11
+ SHORT = 'is_short'
12
+ field :long_or_short, type: :string
13
+ validates :long_or_short, presence: true
14
+
15
+ field :description
16
+
10
17
  has_many :positions, class_name: 'Iro::Position', inverse_of: :strategy
11
18
 
12
- ## multiple strategies per ticker
13
- field :ticker
14
- validates :ticker, presence: true
15
- index({ ticker: 1 })
16
- # belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :strategies
19
+ belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :strategies
20
+
21
+ KIND_COVERED_CALL = 'covered_call'
22
+ KIND_LONG_DEBIT_CALL_SPREAD = 'long_debit_call_spread'
23
+ KIND_SHORT_DEBIT_PUT_SPREAD = 'long_debit_call_spread'
24
+ KINDS = [ nil,
25
+ KIND_COVERED_CALL,
26
+ KIND_LONG_DEBIT_CALL_SPREAD,
27
+ KIND_SHORT_DEBIT_PUT_SPREAD,
28
+ ]
29
+ field :kind
17
30
 
31
+ def kind_short
32
+ case kind
33
+ when KIND_COVERED_CALL
34
+ 'cc'
35
+ when KIND_LONG_DEBIT_CALL_SPREAD
36
+ 'long-spread'
37
+ when KIND_SHORT_DEBIT_PUT_SPREAD
38
+ 'short-spread'
39
+ else
40
+ '@TODO-zez'
41
+ end
42
+ end
18
43
 
19
44
  field :buffer_above_water, type: :float
20
- field :next_max_delta, type: :float
45
+ field :next_max_inner_delta, type: :float
46
+ field :next_max_outer_delta, type: :float
21
47
  field :next_min_strike, type: :float
22
48
  field :threshold_delta, type: :float
23
49
  field :threshold_netp, type: :float
@@ -26,13 +52,53 @@ class Iro::Strategy
26
52
  where( ticker: ticker )
27
53
  end
28
54
 
55
+ def max_gain_covered_call p
56
+ # return p.begin_inner_price
57
+ p.begin_inner_price * 100 - 0.66
58
+ end
59
+ def max_gain_long_debit_call_spread p
60
+ ## 100 * disalloed for gameui
61
+ ( p.inner_strike - p.outer_strike - p.begin_outer_price + p.begin_inner_price ) # - 2*0.66
62
+ end
63
+ def max_gain_short_debit_put_spread p
64
+ ## 100 * disalloed for gameui
65
+ ( p.outer_strike - p.inner_strike - p.begin_outer_price + p.begin_inner_price ) # - 2*0.66
66
+ end
29
67
 
30
- def to_s
31
- slug
68
+ def max_loss_covered_call p
69
+ return 'inf'
70
+ end
71
+ def max_loss_long_debit_call_spread p
72
+ out = 100 * ( p.outer_strike - p.inner_strike )
73
+ end
74
+ def max_loss_short_debit_put_spread p
75
+ out = -100 * ( p.outer_strike - p.inner_strike )
32
76
  end
33
77
 
34
- def self.list
35
- [[nil,nil]] + all.map { |ttt| [ ttt.slug, ttt.id ] }
78
+ def net_amount_covered_call p
79
+ ( p.begin_inner_price - p.end_inner_price ) * 100
36
80
  end
81
+ def net_amount_long_debit_call_spread p
82
+ outer = p.end_outer_price - p.begin_outer_price
83
+ inner = p.begin_inner_price - p.end_inner_price
84
+ out = ( outer + inner ) * 100
85
+ end
86
+ alias_method :net_amount_short_debit_put_spread, :net_amount_long_debit_call_spread
87
+
88
+
89
+ def net_amount_long_debit_call_spread p
90
+ outer = p.end_outer_price - p.begin_outer_price
91
+ inner = p.begin_inner_price - p.end_inner_price
92
+ out = ( outer + inner ) * 100
93
+ end
94
+
37
95
 
96
+
97
+ def to_s
98
+ slug
99
+ end
100
+ def self.list long_or_short = nil
101
+ these = long_or_short ? where( long_or_short: long_or_short ) : all
102
+ [[nil,nil]] + these.map { |ttt| [ ttt.slug, ttt.id ] }
103
+ end
38
104
  end
@@ -1,23 +1,24 @@
1
1
 
2
- .main-header.maxwidth
2
+ .application-main-header.main-header
3
+ .maxwidth
3
4
 
4
- %i.fa.fa-compress.collapse-expand#collapseHeaderEmail
5
- Iron Warbler
5
+ %i.fa.fa-compress.collapse-expand#collapseHeaderTrading
6
+ Iron Warbler
6
7
 
7
- -# .header.collapse-expand#IroMenu
8
- -# %h5.title Iron Warbler
8
+ -# .header.collapse-expand#IroMenu
9
+ -# %h5.title Iron Warbler
9
10
 
10
- %ul
11
- %li= link_to 'ROOT', root_path
12
- %li
13
- = link_to "Stocks (#{Iro::Stock.all.length})", stocks_path
14
- -# %li= link_to 'Options', options_path
15
- -# %li Max Pain
16
- %li
17
- = link_to "Alerts (#{Iro::Alert.all.length})", alerts_path
18
- %li
19
- = link_to "Purses (#{Iro::Purse.all.length})", purses_path
20
- %li
21
- = render '/iro/strategies/header'
11
+ %ul
12
+ %li= link_to 'ROOT', root_path
13
+ %li
14
+ = link_to "Stocks (#{Iro::Stock.all.length})", stocks_path
15
+ -# %li= link_to 'Options', options_path
16
+ -# %li Max Pain
17
+ %li
18
+ = link_to "Alerts (#{Iro::Alert.all.length})", alerts_path
19
+ %li
20
+ = link_to "Purses (#{Iro::Purse.all.length})", purses_path
21
+ %li
22
+ = render '/iro/strategies/header'
22
23
 
23
24