iron_warbler 2.0.7.19 → 2.0.7.21

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 (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>