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.
- checksums.yaml +4 -4
- data/app/assets/javascript/iron_warbler/application.js +2 -0
- data/app/assets/javascript/iron_warbler/gameui.js +9 -0
- data/app/assets/stylesheets/iron_warbler/application.css +13 -3
- data/app/assets/stylesheets/iron_warbler/positions.scss +24 -5
- data/app/assets/stylesheets/iron_warbler/purses_gameui.scss +214 -0
- data/app/assets/stylesheets/iron_warbler/purses_gameui.scss-bk +112 -0
- data/app/assets/stylesheets/iron_warbler/utils.scss +81 -0
- data/app/controllers/iro/api/stocks_controller.rb +87 -0
- data/app/controllers/iro/api_controller.rb +19 -0
- data/app/controllers/iro/positions_controller.rb +35 -4
- data/app/controllers/iro/purses_controller.rb +11 -4
- data/app/controllers/iro/strategies_controller.rb +7 -7
- data/app/helpers/iro/application_helper.rb +5 -2
- data/app/jobs/tda_job.rb +14 -0
- data/app/models/iro/datapoint.rb +48 -8
- data/app/models/iro/position.rb +55 -14
- data/app/models/iro/price_item.rb +51 -1
- data/app/models/iro/purse.rb +4 -0
- data/app/models/iro/stock.rb +5 -2
- data/app/models/iro/strategy.rb +84 -10
- data/app/models/iro/trash/position_covered_call.rb +4 -0
- data/app/models/iro/trash/position_debit_spread.rb +251 -0
- data/app/models/tda/option.rb +7 -7
- data/app/views/iro/_main_header.haml +18 -17
- data/app/views/iro/api/stocks/show.jbuilder +11 -0
- data/app/views/iro/positions/_form.haml +11 -38
- data/app/views/iro/positions/_formpart_4data.haml +46 -0
- data/app/views/iro/positions/_gameui_covered_call.haml +44 -0
- data/app/views/iro/positions/_gameui_covered_call.haml-bk +59 -0
- data/app/views/iro/positions/_gameui_long_debit_call_spread.haml +37 -0
- data/app/views/iro/positions/_gameui_short_debit_put_spread.haml +39 -0
- data/app/views/iro/positions/_header.haml +6 -0
- data/app/views/iro/positions/_header_covered_call.haml +6 -0
- data/app/views/iro/positions/_header_long_debit_call_spread.haml +14 -0
- data/app/views/iro/positions/_header_short_debit_put_spread.haml +1 -0
- data/app/views/iro/positions/_table.haml +120 -123
- data/app/views/iro/positions/roll.haml +83 -0
- data/app/views/iro/positions/trash/_header_short_debit_put_spread.haml +9 -0
- data/app/views/iro/purses/_form.haml +1 -0
- data/app/views/iro/purses/_form_extra_fields.haml +14 -0
- data/app/views/iro/purses/_header.haml +22 -0
- data/app/views/iro/purses/gameui.haml +19 -0
- data/app/views/iro/purses/gameui.haml-bk +44 -0
- data/app/views/iro/purses/gameui.haml-bk2 +89 -0
- data/app/views/iro/purses/show.haml +1 -7
- data/app/views/iro/stocks/_grid_is_long.haml +16 -0
- data/app/views/iro/stocks/_grid_is_short.haml +16 -0
- data/app/views/iro/strategies/_form.haml +12 -5
- data/app/views/iro/strategies/_show.haml +3 -2
- data/app/views/iro/strategies/_table.haml +16 -10
- data/app/views/iro/strategies/index.haml +8 -0
- data/app/views/layouts/iro/application.haml +1 -1
- data/config/routes.rb +15 -1
- data/lib/iro/engine.rb +2 -0
- data/lib/tasks/db_tasks.rake +9 -3
- metadata +31 -8
- data/app/assets/stylesheets/iron_warbler/alerts.css +0 -8
- data/app/assets/stylesheets/iron_warbler/datapoints.css +0 -0
- data/app/assets/stylesheets/iron_warbler/profiles.css +0 -4
- data/app/assets/stylesheets/iron_warbler/strategies.scss +0 -0
- data/app/assets/stylesheets/iron_warbler/utils.css +0 -44
- 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
|
data/app/models/tda/option.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
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
|
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
|
-
|
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
|
-
|
123
|
+
puts! outs, 'outs'
|
124
124
|
return outs
|
125
125
|
end
|
126
126
|
|
@@ -1,23 +1,24 @@
|
|
1
1
|
|
2
|
-
.main-header.
|
2
|
+
.application-main-header.main-header
|
3
|
+
.maxwidth
|
3
4
|
|
4
|
-
|
5
|
-
|
5
|
+
%i.fa.fa-compress.collapse-expand#collapseHeaderTrading
|
6
|
+
Iron Warbler
|
6
7
|
|
7
|
-
|
8
|
-
|
8
|
+
-# .header.collapse-expand#IroMenu
|
9
|
+
-# %h5.title Iron Warbler
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
|
@@ -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
|
-
.
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
16
|
-
|
13
|
+
%label Status
|
14
|
+
= f.select :status, options_for_select( Iro::Position::STATUSES, selected: position.status )
|
17
15
|
|
18
16
|
.field
|
19
|
-
%label
|
20
|
-
= f.select :
|
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
|
-
|
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,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
|
+
|
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} <i>#{pp_percent pos.net_percent}</i>
|