iron_warbler 2.0.7.19 → 2.0.7.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) 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 +24 -5
  6. data/app/assets/stylesheets/iron_warbler/purses_gameui.scss +214 -0
  7. data/app/assets/stylesheets/iron_warbler/purses_gameui.scss-bk +112 -0
  8. data/app/assets/stylesheets/iron_warbler/utils.scss +81 -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 +35 -4
  12. data/app/controllers/iro/purses_controller.rb +11 -4
  13. data/app/controllers/iro/strategies_controller.rb +7 -7
  14. data/app/helpers/iro/application_helper.rb +5 -2
  15. data/app/jobs/tda_job.rb +14 -0
  16. data/app/models/iro/datapoint.rb +48 -8
  17. data/app/models/iro/position.rb +55 -14
  18. data/app/models/iro/price_item.rb +51 -1
  19. data/app/models/iro/purse.rb +4 -0
  20. data/app/models/iro/stock.rb +5 -2
  21. data/app/models/iro/strategy.rb +84 -10
  22. data/app/models/iro/trash/position_covered_call.rb +4 -0
  23. data/app/models/iro/trash/position_debit_spread.rb +251 -0
  24. data/app/models/tda/option.rb +7 -7
  25. data/app/views/iro/_main_header.haml +18 -17
  26. data/app/views/iro/api/stocks/show.jbuilder +11 -0
  27. data/app/views/iro/positions/_form.haml +11 -38
  28. data/app/views/iro/positions/_formpart_4data.haml +46 -0
  29. data/app/views/iro/positions/_gameui_covered_call.haml +44 -0
  30. data/app/views/iro/positions/_gameui_covered_call.haml-bk +59 -0
  31. data/app/views/iro/positions/_gameui_long_debit_call_spread.haml +37 -0
  32. data/app/views/iro/positions/_gameui_short_debit_put_spread.haml +39 -0
  33. data/app/views/iro/positions/_header.haml +6 -0
  34. data/app/views/iro/positions/_header_covered_call.haml +6 -0
  35. data/app/views/iro/positions/_header_long_debit_call_spread.haml +14 -0
  36. data/app/views/iro/positions/_header_short_debit_put_spread.haml +1 -0
  37. data/app/views/iro/positions/_table.haml +120 -123
  38. data/app/views/iro/positions/roll.haml +83 -0
  39. data/app/views/iro/positions/trash/_header_short_debit_put_spread.haml +9 -0
  40. data/app/views/iro/purses/_form.haml +1 -0
  41. data/app/views/iro/purses/_form_extra_fields.haml +14 -0
  42. data/app/views/iro/purses/_header.haml +22 -0
  43. data/app/views/iro/purses/gameui.haml +19 -0
  44. data/app/views/iro/purses/gameui.haml-bk +44 -0
  45. data/app/views/iro/purses/gameui.haml-bk2 +89 -0
  46. data/app/views/iro/purses/show.haml +1 -7
  47. data/app/views/iro/stocks/_grid_is_long.haml +16 -0
  48. data/app/views/iro/stocks/_grid_is_short.haml +16 -0
  49. data/app/views/iro/strategies/_form.haml +12 -5
  50. data/app/views/iro/strategies/_show.haml +3 -2
  51. data/app/views/iro/strategies/_table.haml +16 -10
  52. data/app/views/iro/strategies/index.haml +8 -0
  53. data/app/views/layouts/iro/application.haml +1 -1
  54. data/config/routes.rb +15 -1
  55. data/lib/iro/engine.rb +2 -0
  56. data/lib/tasks/db_tasks.rake +9 -3
  57. metadata +31 -8
  58. data/app/assets/stylesheets/iron_warbler/alerts.css +0 -8
  59. data/app/assets/stylesheets/iron_warbler/datapoints.css +0 -0
  60. data/app/assets/stylesheets/iron_warbler/profiles.css +0 -4
  61. data/app/assets/stylesheets/iron_warbler/strategies.scss +0 -0
  62. data/app/assets/stylesheets/iron_warbler/utils.css +0 -44
  63. data/app/jobs/iro/application_job.rb-trash +0 -4
@@ -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
@@ -13,7 +13,7 @@ class Tda::Option
13
13
  def self.get_chain params
14
14
  opts = { symbol: params[:ticker] } ## use 'GME' as symbol here even though a symbol is eg 'GME_021023P2.5'
15
15
  query = { apikey: ::TD_AMERITRADE[:apiKey] }.merge opts
16
- # puts! query, 'input opts'
16
+ puts! query, 'input opts'
17
17
 
18
18
  path = "/v1/marketdata/chains"
19
19
  out = self.get path, { query: query }
@@ -55,7 +55,7 @@ class Tda::Option
55
55
  ## 2023-03-18 _vp_ This is what I should be using to check if a position should be rolled.
56
56
  ##
57
57
  def self.get_quote params
58
- ::Tda::Option.get_quotes(params)[0]
58
+ OpenStruct.new ::Tda::Option.get_quotes(params)[0]
59
59
  end
60
60
 
61
61
  ##
@@ -79,18 +79,18 @@ class Tda::Option
79
79
  if params[s]
80
80
  opts[s] = params[s]
81
81
  else
82
- raise Iwa::InputError.new("Invalid input, missing '#{s}'.")
82
+ raise Iro::InputError.new("Invalid input, missing '#{s}'.")
83
83
  end
84
84
  end
85
85
  if params[:expirationDate]
86
86
  opts[:fromDate] = opts[:toDate] = params[:expirationDate]
87
87
  else
88
- raise Iwa::InputError.new("Invalid input, missing 'date'.")
88
+ raise Iro::InputError.new("Invalid input, missing 'date'.")
89
89
  end
90
90
  if params[:ticker]
91
91
  opts[:symbol] = params[:ticker].upcase
92
92
  else
93
- raise Iwa::InputError.new("Invalid input, missing 'ticker'.")
93
+ raise Iro::InputError.new("Invalid input, missing 'ticker'.")
94
94
  end
95
95
 
96
96
  if params[:strike]
@@ -98,7 +98,7 @@ class Tda::Option
98
98
  end
99
99
 
100
100
  query = { apikey: ::TD_AMERITRADE[:apiKey] }.merge opts
101
- # puts! query, 'input opts'
101
+ puts! query, 'input opts'
102
102
 
103
103
  path = "/v1/marketdata/chains"
104
104
  out = self.get path, { query: query }
@@ -120,7 +120,7 @@ class Tda::Option
120
120
  end
121
121
  end
122
122
 
123
- # puts! outs, 'outs'
123
+ puts! outs, 'outs'
124
124
  return outs
125
125
  end
126
126
 
@@ -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
 
@@ -0,0 +1,11 @@
1
+
2
+ json.array! @datapoints do |p|
3
+ json.date p[:quote_at].in_time_zone('UTC').to_date
4
+ json.quote_at p[:quote_at]
5
+ json.open p[:open]
6
+ json.high p[:high]
7
+ json.low p[:low]
8
+ json.close p[:value]
9
+ json.volume p[:volume]
10
+ end
11
+
@@ -1,59 +1,32 @@
1
1
 
2
- .positions--form
2
+ .positions--form{ class: params[:long_or_short] || position.strategy&.long_or_short }
3
3
  = form_for position do |f|
4
4
  .actions
5
5
  = f.submit
6
6
 
7
- .field
8
- %label Purse
9
- -# = f.select :purse_id, options_for_select( @
10
- = f.text_field :purse_id
11
-
12
- %label Status
13
- = f.select :status, options_for_select( Iro::Position::STATUSES, selected: position.status )
7
+ .d-flex
8
+ .field
9
+ %label Purse
10
+ -# = f.select :purse_id, options_for_select( @
11
+ = f.text_field :purse_id
14
12
 
15
- %br
16
- %br
13
+ %label Status
14
+ = f.select :status, options_for_select( Iro::Position::STATUSES, selected: position.status )
17
15
 
18
16
  .field
19
- %label Ticker
20
- = f.select :ticker, options_for_select( @tickers_list, selected: position.ticker )
21
-
22
-
23
- %label Kind
24
- = f.select :kind, options_for_select( Iro::Position::KINDS, selected: position.kind )
17
+ %label Stock
18
+ = f.select :stock_id, options_for_select( @stocks_list, selected: position.stock_id )
25
19
  %label Strategy
26
20
  = f.select :strategy_id, options_for_select( @strategies_list, selected: position.strategy_id )
27
21
 
28
-
29
- %label Strike
30
- = f.text_field :strike
31
-
32
22
  .field
33
23
  %label Expires on
34
24
  = f.text_field :expires_on
35
-
36
-
37
25
  %label Quantity
38
26
  = f.text_field :quantity
39
27
 
40
28
  %br
41
- %br
42
-
43
- .flex-row
44
- %label Begin on
45
- = f.text_field :begin_on
46
- %label Begin price
47
- = f.text_field :begin_price
48
- %label Begin delta
49
- = f.text_field :begin_delta
50
- .flex-row
51
- %label End on
52
- = f.text_field :end_on
53
- %label End price
54
- = f.text_field :end_price
55
- %label End delta
56
- = f.text_field :end_delta
29
+ = render 'formpart_4data', f: f, position: position
57
30
 
58
31
  .actions
59
32
  = f.submit
@@ -0,0 +1,46 @@
1
+ .field
2
+ %label Begin on
3
+ = f.text_field :begin_on
4
+
5
+ .long-or-short-item
6
+ .d-flex
7
+ .field
8
+ %label Outer Strike
9
+ = f.number_field :outer_strike, step: 0.01
10
+ .field
11
+ %label Begin outer price
12
+ = f.text_field :begin_outer_price
13
+ .field
14
+ %label Begin outer delta
15
+ = f.text_field :begin_outer_delta
16
+
17
+ .d-flex
18
+ .field
19
+ %label Inner Strike
20
+ = f.number_field :inner_strike, step: 0.01
21
+ .field
22
+ %label Begin inner price
23
+ = f.text_field :begin_inner_price
24
+ .field
25
+ %label Begin inner delta
26
+ = f.text_field :begin_inner_delta
27
+
28
+ %br
29
+ .flex-row
30
+ %label End on
31
+ = f.text_field :end_on
32
+ .long-or-short-item
33
+ .d-flex
34
+ .field
35
+ %label End outer price
36
+ = f.text_field :end_outer_price
37
+ .field
38
+ %label End outer delta
39
+ = f.text_field :end_outer_delta
40
+ .d-flex
41
+ .field
42
+ %label End inner price
43
+ = f.text_field :end_inner_price
44
+ .field
45
+ %label End inner delta
46
+ = f.text_field :end_inner_delta
@@ -0,0 +1,44 @@
1
+
2
+ - pos = position
3
+ - stock = pos.stock
4
+ - nearest_strike = stock.last.round
5
+ - u = @unit # pixels per dollar
6
+
7
+ .collapse-expand.d-flex{ id: "gameui-pos-#{pos.id}" }
8
+ [<>]
9
+ .maxwidth= render "/iro/positions/header", pos: pos
10
+ .a
11
+ = render "/iro/positions/header_#{pos.strategy.kind}", pos: pos
12
+ .StockCoordinatesW
13
+ .StockCoordinates{ style: "height: #{pos.purse.height}px " }
14
+ = render "/iro/stocks/grid_#{pos.strategy.long_or_short}", stock: stock
15
+
16
+ .Origin{ style: "left: #{ ( nearest_strike - stock.last )* u}px" }
17
+ .label Last: #{pp_amount stock.last}
18
+ .c
19
+
20
+ -## Good, remove trash, leave as implemented.
21
+ -# - left = "#{ (stock.last - position.inner_strike - position.begin_inner_price) * u}px"
22
+ -# - width = "#{ position.begin_inner_price * u}px"
23
+ - left = "#{ (stock.last - pos.inner_strike) * u}px"
24
+ - width = "0px"
25
+ .PositionW{ style: "left: #{left} ; width: #{width} " }
26
+ .Position
27
+ .PositionC
28
+
29
+ - if position.net_amount >= 0
30
+ .Net.NetPositive{ style: "width: #{ (position.net_amount / 100) * u }px; right: 0" }
31
+ .label
32
+ net
33
+ = pp_amount position.net_amount
34
+ - else
35
+ .Net.NetNegative{ style: "width: #{ (-1 * position.net_amount / 100) * u }px; left: 100%" }
36
+ .label
37
+ net
38
+ = pp_amount position.net_amount
39
+
40
+ .Breakeven{ style: "width: #{ pos.begin_inner_price * u }px" }
41
+ .label
42
+ Breakeven:
43
+ = pos.begin_inner_price
44
+
@@ -0,0 +1,59 @@
1
+
2
+ - unit = u = 50 # pixels per dollar
3
+ - grid_size = 100 # dollars to each side of origin
4
+ .purses-gameui.padded
5
+ = render '/iro/purses/header', purse: @purse
6
+
7
+ - @positions.each_with_index do |position, idx|
8
+ - stock = position.stock
9
+ - if idx == 0
10
+ %h4= stock
11
+ - else
12
+ - prev_ = @positions[idx-1]
13
+ - if stock != prev_.stock
14
+ %hr
15
+ %h4= stock
16
+
17
+ .header
18
+ = position.quantity
19
+ = stock
20
+ = position.expires_on.to_datetime.strftime("%b %d")
21
+ = link_to '[roll]', roll_position_path(position)
22
+ = link_to '[~]', edit_position_path(position)
23
+
24
+ - nearest_strike = stock.last.round
25
+ .StockCoordinatesW
26
+
27
+ .StockCoordinates
28
+ .grid-mark.mark0
29
+ .label= nearest_strike
30
+ - (1...grid_size).each_with_index do |idx|
31
+ .grid-mark{ class: "mark#{idx}", style: "left: -#{idx * u}px" }
32
+ .label
33
+ = nearest_strike + idx
34
+ .grid-mark{ class: "mark-#{idx}", style: "left: #{idx * u}px" }
35
+ .label
36
+ = nearest_strike - idx
37
+ .Origin{ style: "left: #{ ( nearest_strike - stock.last )* u}px" }
38
+ .label
39
+ Last:
40
+ = stock.last
41
+
42
+ - left = "#{ (stock.last - position.inner_strike - position.begin_inner_price) * u}px"
43
+ - width = "#{ position.begin_inner_price * u}px"
44
+ .PositionW{ style: "left: #{left}; width: #{width}; " }
45
+
46
+ .Position
47
+ - if position.net_amount >= 0
48
+ .Net.NetPositive{ style: "width: #{ (position.net_amount / 100) * u }px; right: 0" }
49
+ .label
50
+ net
51
+ = pp_amount position.net_amount
52
+ - else
53
+ .Net.NetNegative{ style: "width: #{ (-1 * position.net_amount / 100) * u }px; left: 100%" }
54
+ .label
55
+ net
56
+ = pp_amount position.net_amount
57
+
58
+ %br
59
+ %br
@@ -0,0 +1,37 @@
1
+
2
+ - pos = position
3
+ - stock = pos.stock
4
+ - nearest_strike = stock.last.round
5
+ - u = @purse.unit # pixels per dollar
6
+
7
+ .collapse-expand.d-flex{ id: "gameui-pos-#{pos.id}" }
8
+ [<>]
9
+ .maxwidth= render "/iro/positions/header", pos: pos
10
+ .a
11
+ = render "/iro/positions/header_#{pos.strategy.kind}", pos: pos
12
+ .StockCoordinatesW
13
+ .StockCoordinates{ style: "height: #{pos.purse.height}px " }
14
+ = render "/iro/stocks/grid_#{pos.strategy.long_or_short}", stock: stock
15
+
16
+ .Origin{ style: "left: #{ ( nearest_strike - stock.last )* u}px" }
17
+ .label Last: #{pp_amount stock.last}
18
+ .c
19
+
20
+ - left = "#{ ( pos.outer_strike - stock.last ) * u}px"
21
+ - width = "#{ ( pos.inner_strike - pos.outer_strike ) * u}px"
22
+ .PositionW{ style: "left: #{left}; width: #{width}; " }
23
+ .Position
24
+ .MaxGain{ style: "width: #{pos.max_gain * u}px" }
25
+
26
+ - if pos.net_amount >= 0
27
+ .Net.NetPositive{ style: "width: #{ (pos.net_amount / 100) * u }px; right: 0" }
28
+ .label
29
+ net
30
+ = pp_amount pos.net_amount
31
+ - else
32
+ .Net.NetNegative{ style: "width: #{ (-1 * pos.net_amount / 100) * u }px; left: 100%" }
33
+ .label
34
+ net
35
+ = pp_amount pos.net_amount
36
+ .c
37
+
@@ -0,0 +1,39 @@
1
+
2
+ - pos = position
3
+ - stock = pos.stock
4
+ - nearest_strike = stock.last.round
5
+ - u = @unit # pixels per dollar
6
+
7
+
8
+ .collapse-expand.d-flex{ id: "gameui-pos-#{pos.id}" }
9
+ [<>]
10
+ .maxwidth= render "/iro/positions/header", pos: pos
11
+ .a
12
+ = render "/iro/positions/header_#{pos.strategy.kind}", pos: pos
13
+ .StockCoordinatesW
14
+ .StockCoordinates{ style: "height: #{pos.purse.height}px " }
15
+ = render "/iro/stocks/grid_#{pos.strategy.long_or_short}", stock: stock
16
+
17
+ .Origin{ style: "left: #{ ( nearest_strike - stock.last )* u}px" }
18
+ .label Last: #{pp_amount stock.last}
19
+ .c
20
+
21
+ -## these are different
22
+ - left = "#{ ( stock.last - pos.outer_strike ) * u}px"
23
+ - width = "#{ ( pos.outer_strike - pos.inner_strike ) * u}px"
24
+ .PositionW{ style: "left: #{left}; width: #{width}; " }
25
+ .Position
26
+ .MaxGain{ style: "width: #{pos.max_gain * u}px" }
27
+
28
+ - if pos.net_amount >= 0
29
+ .Net.NetPositive{ style: "width: #{ (pos.net_amount / 100) * u }px; right: 0" }
30
+ .label
31
+ net
32
+ = pp_amount pos.net_amount
33
+ - else
34
+ .Net.NetNegative{ style: "width: #{ (-1 * pos.net_amount / 100) * u }px; left: 100%" }
35
+ .label
36
+ net
37
+ = pp_amount pos.net_amount
38
+ .c
39
+
@@ -0,0 +1,6 @@
1
+
2
+ .positions--header.maxwidth
3
+ = pos
4
+ = link_to '[roll]', roll_position_path(pos)
5
+ = link_to '[~]', edit_position_path(pos)
6
+ -# = render "/iro/positions/header_#{pos.strategy.kind}", pos: pos
@@ -0,0 +1,6 @@
1
+
2
+ %i.fa.fa-expand.collapse-expand.floaty-collapse{ id: "gameui-pos-detail-#{pos.id}" }
3
+ .maxwidth
4
+ %ul.m-0.p-0
5
+ %li <b>begin_inner_price:</b> #{pp_amount pos.begin_inner_price}
6
+ %li <b>Net:</b> #{pp_amount pos.net_amount} &nbsp; <i>#{pp_percent pos.net_percent}</i>
@@ -0,0 +1,14 @@
1
+
2
+
3
+ -## Same file for the spreads
4
+ %i.fa.fa-expand.collapse-expand.floaty-collapse{ id: "gameui-pos-detail-#{pos.id}" }
5
+ .maxwidth
6
+ %ul.m-0.p-0
7
+ %li <b>outer,inner_strike:</b> #{pp_amount pos.outer_strike} -> #{pp_amount pos.inner_strike}
8
+ %li
9
+ <b>begin_outer,inner_price:</b> #{pp_amount pos.begin_outer_price} -> #{pp_amount pos.begin_inner_price}
10
+ &nbsp;&nbsp;
11
+ -## yes *100
12
+ <b>max gain:</b> #{pp_amount pos.max_gain} :: #{pp_amount pos.max_gain * 100 * pos.q}
13
+ - ## no *100
14
+ %li <b>Net:</b> #{pp_amount pos.net_amount} :: #{pp_amount pos.net_amount * pos.q} &nbsp;&nbsp; <i>#{pp_percent pos.net_percent}</i>