iron_warbler 2.0.7.22 → 2.0.7.23
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.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/iron_warbler/application.css +12 -0
- data/app/assets/stylesheets/iron_warbler/positions.scss +2 -0
- data/app/assets/stylesheets/iron_warbler/positions_gameui.scss +11 -0
- data/app/assets/stylesheets/iron_warbler/purses_gameui.scss +6 -2
- data/app/assets/stylesheets/iron_warbler/purses_summary.scss +98 -0
- data/app/assets/stylesheets/iron_warbler/utils.scss +4 -0
- data/app/controllers/iro/alerts_controller.rb +2 -0
- data/app/controllers/iro/application_controller.rb +13 -0
- data/app/controllers/iro/positions_controller.rb +197 -23
- data/app/controllers/iro/purses_controller.rb +60 -6
- data/app/controllers/iro/stocks_controller.rb +30 -18
- data/app/controllers/iro/strategies_controller.rb +12 -1
- data/app/models/iro/alert.rb +1 -0
- data/app/models/iro/option.rb +1 -0
- data/app/models/iro/position.rb +124 -56
- data/app/models/iro/purse.rb +15 -4
- data/app/models/iro/stock.rb +3 -0
- data/app/models/iro/strategy.rb +122 -27
- data/app/models/tda/option.rb +3 -3
- data/app/views/iro/_main_header.haml +28 -17
- data/app/views/iro/application/home.haml +6 -1
- data/app/views/iro/positions/_form.haml +1 -2
- data/app/views/iro/positions/_gameui_covered_call.haml +10 -13
- data/app/views/iro/positions/_gameui_covered_call.haml-bk +8 -0
- data/app/views/iro/positions/_gameui_long_debit_call_spread.haml +5 -4
- data/app/views/iro/positions/_gameui_short_debit_put_spread.haml +5 -4
- data/app/views/iro/positions/_header.haml +2 -2
- data/app/views/iro/positions/_header_covered_call.haml +7 -1
- data/app/views/iro/positions/_header_long_debit_call_spread.haml +19 -1
- data/app/views/iro/positions/_prepare_covered_call.haml +25 -0
- data/app/views/iro/positions/_prepare_long_debit_call_spread.haml +23 -0
- data/app/views/iro/positions/_prepare_short_debit_put_spread.haml +23 -0
- data/app/views/iro/positions/_table.haml +33 -24
- data/app/views/iro/positions/prepare.haml +24 -0
- data/app/views/iro/positions/roll-cc.haml-bk +40 -0
- data/app/views/iro/positions/roll.haml-trash +42 -0
- data/app/views/iro/purses/_form.haml +9 -0
- data/app/views/iro/purses/_form_extra_fields.haml +25 -13
- data/app/views/iro/purses/_header.haml +15 -16
- data/app/views/iro/purses/_summary.haml +69 -0
- data/app/views/iro/purses/gameui.haml +12 -7
- data/app/views/iro/purses/index.haml +3 -1
- data/app/views/iro/purses/show.haml +5 -1
- data/app/views/iro/stocks/_form.haml +5 -0
- data/app/views/iro/stocks/_grid_is_long.haml +2 -2
- data/app/views/iro/stocks/_grid_is_short.haml +2 -2
- data/app/views/iro/stocks/index.haml +3 -2
- data/app/views/iro/strategies/_form.haml +12 -6
- data/app/views/iro/strategies/_show.haml +3 -3
- data/app/views/iro/strategies/_table.haml +15 -6
- data/app/views/iro/strategies/show.haml +14 -0
- data/app/views/layouts/iro/application.haml +4 -0
- data/config/routes.rb +6 -2
- metadata +12 -4
- data/app/views/iro/positions/roll.haml +0 -83
- data/app/views/iro/positions/trash/_header_short_debit_put_spread.haml +0 -9
data/app/models/iro/option.rb
CHANGED
data/app/models/iro/position.rb
CHANGED
@@ -2,9 +2,10 @@
|
|
2
2
|
class Iro::Position
|
3
3
|
include Mongoid::Document
|
4
4
|
include Mongoid::Timestamps
|
5
|
+
include Mongoid::Paranoia
|
5
6
|
store_in collection: 'iro_positions'
|
6
7
|
|
7
|
-
attr_accessor :
|
8
|
+
attr_accessor :next_gain_loss_amount
|
8
9
|
|
9
10
|
STATUS_ACTIVE = 'active'
|
10
11
|
STATUS_PROPOSED = 'proposed'
|
@@ -53,8 +54,15 @@ class Iro::Position
|
|
53
54
|
field :end_inner_price, type: :float
|
54
55
|
field :end_inner_delta, type: :float
|
55
56
|
|
57
|
+
def begin_delta
|
58
|
+
strategy.send("begin_delta_#{strategy.kind}", self)
|
59
|
+
end
|
60
|
+
def end_delta
|
61
|
+
strategy.send("end_delta_#{strategy.kind}", self)
|
62
|
+
end
|
63
|
+
|
56
64
|
def breakeven
|
57
|
-
strategy.
|
65
|
+
strategy.send("breakeven_#{strategy.kind}", self)
|
58
66
|
end
|
59
67
|
|
60
68
|
def current_underlying_strike
|
@@ -87,6 +95,9 @@ class Iro::Position
|
|
87
95
|
def max_loss # each
|
88
96
|
strategy.send("max_loss_#{strategy.kind}", self)
|
89
97
|
end
|
98
|
+
# def gain_loss_amount
|
99
|
+
# strategy.send("gain_loss_amount_#{strategy.kind}", self)
|
100
|
+
# end
|
90
101
|
|
91
102
|
|
92
103
|
field :next_delta, type: :float
|
@@ -94,52 +105,122 @@ class Iro::Position
|
|
94
105
|
field :next_symbol
|
95
106
|
field :next_mark
|
96
107
|
field :next_reasons, type: :array, default: []
|
97
|
-
field :
|
98
|
-
|
99
|
-
|
100
|
-
##
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
108
|
+
field :rollp, type: :float
|
109
|
+
|
110
|
+
|
111
|
+
## covered call
|
112
|
+
# def sync
|
113
|
+
# puts! [ inner_strike, expires_on, stock.ticker ], 'init sync'
|
114
|
+
# out = Tda::Option.get_quote({
|
115
|
+
# contractType: 'CALL',
|
116
|
+
# strike: inner_strike,
|
117
|
+
# expirationDate: expires_on,
|
118
|
+
# ticker: stock.ticker,
|
119
|
+
# })
|
120
|
+
# puts! out, 'sync'
|
121
|
+
# self.end_inner_price = ( out.bid + out.ask ) / 2
|
122
|
+
# self.end_inner_delta = out.delta
|
123
|
+
# end
|
124
|
+
|
125
|
+
## long call spread
|
126
|
+
# def sync
|
127
|
+
# # puts! [
|
128
|
+
# # [ inner_strike, expires_on, stock.ticker ],
|
129
|
+
# # [ outer_strike, expires_on, stock.ticker ],
|
130
|
+
# # ], 'init sync inner, outer'
|
131
|
+
# inner = Tda::Option.get_quote({
|
132
|
+
# contractType: 'CALL',
|
133
|
+
# strike: inner_strike,
|
134
|
+
# expirationDate: expires_on,
|
135
|
+
# ticker: stock.ticker,
|
136
|
+
# })
|
137
|
+
# outer = Tda::Option.get_quote({
|
138
|
+
# contractType: 'CALL',
|
139
|
+
# strike: outer_strike,
|
140
|
+
# expirationDate: expires_on,
|
141
|
+
# ticker: stock.ticker,
|
142
|
+
# })
|
143
|
+
# puts! [inner, outer], 'sync inner, outer'
|
144
|
+
# self.end_outer_price = ( outer.bid + outer.ask ) / 2
|
145
|
+
# self.end_outer_delta = outer.delta
|
146
|
+
|
147
|
+
# self.end_inner_price = ( inner.bid + inner.ask ) / 2
|
148
|
+
# self.end_inner_delta = inner.delta
|
149
|
+
# end
|
150
|
+
|
151
|
+
def sync
|
152
|
+
put_call = Iro::Strategy::LONG == strategy.long_or_short ? 'CALL' : 'PUT'
|
153
|
+
puts! [
|
154
|
+
[ inner_strike, expires_on, stock.ticker ],
|
155
|
+
[ outer_strike, expires_on, stock.ticker ],
|
156
|
+
], 'init sync inner, outer'
|
157
|
+
inner = Tda::Option.get_quote({
|
158
|
+
contractType: put_call,
|
159
|
+
strike: inner_strike,
|
160
|
+
expirationDate: expires_on,
|
161
|
+
ticker: stock.ticker,
|
162
|
+
})
|
163
|
+
outer = Tda::Option.get_quote({
|
164
|
+
contractType: put_call,
|
165
|
+
strike: outer_strike,
|
166
|
+
expirationDate: expires_on,
|
167
|
+
ticker: stock.ticker,
|
110
168
|
})
|
169
|
+
puts! [inner, outer], 'sync inner, outer'
|
170
|
+
self.end_outer_price = ( outer.bid + outer.ask ) / 2
|
171
|
+
self.end_outer_delta = outer.delta
|
111
172
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
173
|
+
self.end_inner_price = ( inner.bid + inner.ask ) / 2
|
174
|
+
self.end_inner_delta = inner.delta
|
175
|
+
end
|
176
|
+
def sync_short_debit_put_spread
|
177
|
+
puts! [
|
178
|
+
[ inner_strike, expires_on, stock.ticker ],
|
179
|
+
[ outer_strike, expires_on, stock.ticker ],
|
180
|
+
], 'init sync inner, outer'
|
181
|
+
inner = Tda::Option.get_quote({
|
182
|
+
contractType: 'PUT',
|
183
|
+
strike: inner_strike,
|
184
|
+
expirationDate: expires_on,
|
185
|
+
ticker: stock.ticker,
|
186
|
+
})
|
187
|
+
outer = Tda::Option.get_quote({
|
188
|
+
contractType: 'PUT',
|
189
|
+
strike: outer_strike,
|
190
|
+
expirationDate: expires_on,
|
191
|
+
ticker: stock.ticker,
|
192
|
+
})
|
193
|
+
puts! [inner, outer], 'sync inner, outer'
|
194
|
+
self.end_outer_price = ( outer.bid + outer.ask ) / 2
|
195
|
+
self.end_outer_delta = outer.delta
|
126
196
|
|
127
|
-
|
128
|
-
|
129
|
-
|
197
|
+
self.end_inner_price = ( inner.bid + inner.ask ) / 2
|
198
|
+
self.end_inner_delta = inner.delta
|
199
|
+
end
|
130
200
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
next_symbol: next_position[:symbol],
|
135
|
-
next_mark: next_position[:mark],
|
136
|
-
should_rollp: out,
|
137
|
-
# status: Iro::Position::STATE_PROPOSED,
|
138
|
-
})
|
201
|
+
##
|
202
|
+
## decisions
|
203
|
+
##
|
139
204
|
|
140
|
-
|
141
|
-
|
142
|
-
|
205
|
+
def calc_rollp
|
206
|
+
self.next_reasons = []
|
207
|
+
self.next_symbol = nil
|
208
|
+
self.next_delta = nil
|
209
|
+
|
210
|
+
out = strategy.send( "calc_rollp_#{strategy.kind}", self )
|
211
|
+
|
212
|
+
self.rollp = out[0]
|
213
|
+
self.next_reasons.push out[1]
|
214
|
+
save
|
215
|
+
|
216
|
+
# update({
|
217
|
+
# next_delta: next_position[:delta],
|
218
|
+
# next_outcome: next_position[:mark] - end_price,
|
219
|
+
# next_symbol: next_position[:symbol],
|
220
|
+
# next_mark: next_position[:mark],
|
221
|
+
# should_rollp: out,
|
222
|
+
# # status: Iro::Position::STATE_PROPOSED,
|
223
|
+
# })
|
143
224
|
end
|
144
225
|
|
145
226
|
|
@@ -149,19 +230,6 @@ class Iro::Position
|
|
149
230
|
( expires_on.to_date - Time.now.to_date ).to_i < 7
|
150
231
|
end
|
151
232
|
|
152
|
-
## If I'm near below water
|
153
|
-
##
|
154
|
-
## expires_on = cc.expires_on ; strategy = cc.strategy ; strike = cc.strike ; nil
|
155
|
-
def must_roll?
|
156
|
-
if ( current_underlying_strike + strategy.buffer_above_water ) > strike
|
157
|
-
return true
|
158
|
-
end
|
159
|
-
## @TODO: This one should not happen, I should log appropriately. _vp_ 2023-03-19
|
160
|
-
if ( expires_on.to_date - Time.now.to_date ).to_i < 1
|
161
|
-
return true
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
233
|
## strike = cc.strike ; strategy = cc.strategy ; nil
|
166
234
|
def near_below_water?
|
167
235
|
strike < current_underlying_strike + strategy.buffer_above_water
|
data/app/models/iro/purse.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
class Iro::Purse
|
3
3
|
include Mongoid::Document
|
4
4
|
include Mongoid::Timestamps
|
5
|
+
include Mongoid::Paranoia
|
5
6
|
store_in collection: 'iro_purses'
|
6
7
|
|
7
8
|
field :slug
|
@@ -10,12 +11,22 @@ class Iro::Purse
|
|
10
11
|
|
11
12
|
has_many :positions, class_name: 'Iro::Position', inverse_of: :purse
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
field :
|
14
|
+
belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :strategies
|
15
|
+
|
16
|
+
field :unit, type: :integer, default: 10
|
17
|
+
# field :height, type: :integer, default: 100
|
18
|
+
field :mark_every_n_usd, type: :float, default: 1
|
19
|
+
field :n_next_positions, type: :integer, default: 5
|
20
|
+
## with unit 10, sum_scale .001
|
21
|
+
## with unit 100, sum_scale .0001
|
22
|
+
field :summary_scale, type: :float, default: 0.001
|
23
|
+
|
24
|
+
field :available_amount, type: :float
|
16
25
|
|
17
26
|
def to_s
|
18
27
|
slug
|
19
28
|
end
|
20
|
-
|
29
|
+
def self.list
|
30
|
+
[[nil,nil]] + all.map { |p| [p, p.id] }
|
31
|
+
end
|
21
32
|
end
|
data/app/models/iro/stock.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
class Iro::Stock
|
3
3
|
include Mongoid::Document
|
4
4
|
include Mongoid::Timestamps
|
5
|
+
include Mongoid::Paranoia
|
5
6
|
store_in collection: 'iro_stocks'
|
6
7
|
|
7
8
|
STATUS_ACTIVE = 'active'
|
@@ -17,9 +18,11 @@ class Iro::Stock
|
|
17
18
|
index({ ticker: -1 }, { unique: true })
|
18
19
|
|
19
20
|
field :last, type: :float
|
21
|
+
field :options_price_increment, type: :float
|
20
22
|
|
21
23
|
has_many :positions, class_name: 'Iro::Position', inverse_of: :stock
|
22
24
|
has_many :strategies, class_name: 'Iro::Strategy', inverse_of: :stock
|
25
|
+
has_many :purses, class_name: 'Iro::Purse', inverse_of: :stock
|
23
26
|
|
24
27
|
def to_s
|
25
28
|
ticker
|
data/app/models/iro/strategy.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
class Iro::Strategy
|
3
3
|
include Mongoid::Document
|
4
4
|
include Mongoid::Timestamps
|
5
|
+
include Mongoid::Paranoia
|
5
6
|
store_in collection: 'iro_strategies'
|
6
7
|
|
7
8
|
field :slug
|
@@ -20,7 +21,7 @@ class Iro::Strategy
|
|
20
21
|
|
21
22
|
KIND_COVERED_CALL = 'covered_call'
|
22
23
|
KIND_LONG_DEBIT_CALL_SPREAD = 'long_debit_call_spread'
|
23
|
-
KIND_SHORT_DEBIT_PUT_SPREAD = '
|
24
|
+
KIND_SHORT_DEBIT_PUT_SPREAD = 'short_debit_put_spread'
|
24
25
|
KINDS = [ nil,
|
25
26
|
KIND_COVERED_CALL,
|
26
27
|
KIND_LONG_DEBIT_CALL_SPREAD,
|
@@ -42,27 +43,31 @@ class Iro::Strategy
|
|
42
43
|
end
|
43
44
|
|
44
45
|
field :buffer_above_water, type: :float
|
45
|
-
field :next_max_inner_delta, type: :float
|
46
|
-
field :next_max_outer_delta, type: :float
|
47
|
-
field :next_min_strike, type: :float
|
48
46
|
field :threshold_delta, type: :float
|
49
47
|
field :threshold_netp, type: :float
|
50
48
|
|
49
|
+
field :next_inner_delta, type: :float
|
50
|
+
field :next_outer_delta, type: :float
|
51
|
+
field :next_inner_strike, type: :float
|
52
|
+
field :next_outer_strike, type: :float
|
53
|
+
field :next_spread_amount, type: :float # e.g. $20 for a $2000 NVDA spread
|
54
|
+
|
55
|
+
|
51
56
|
def self.for_ticker ticker
|
52
57
|
where( ticker: ticker )
|
53
58
|
end
|
54
59
|
|
55
|
-
def
|
56
|
-
p.inner_strike - p.begin_outer_price + p.begin_inner_price
|
57
|
-
end
|
58
|
-
|
59
|
-
def breakeven p
|
60
|
+
def breakeven_covered_call p
|
60
61
|
p.inner_strike + p.begin_inner_price
|
61
62
|
end
|
63
|
+
def breakeven_long_debit_call_spread p
|
64
|
+
p.inner_strike - p.max_gain # p.begin_outer_price + p.begin_inner_price
|
65
|
+
end
|
66
|
+
alias_method :breakeven_short_debit_put_spread, :breakeven_long_debit_call_spread
|
62
67
|
|
63
68
|
def max_gain_covered_call p
|
64
69
|
# return p.begin_inner_price
|
65
|
-
p.begin_inner_price * 100 - 0.66
|
70
|
+
p.begin_inner_price * 100 - 0.66 # @TODO: is this *100 really?
|
66
71
|
end
|
67
72
|
def max_gain_long_debit_call_spread p
|
68
73
|
## 100 * disalloed for gameui
|
@@ -73,40 +78,130 @@ class Iro::Strategy
|
|
73
78
|
( p.outer_strike - p.inner_strike - p.begin_outer_price + p.begin_inner_price ) # - 2*0.66
|
74
79
|
end
|
75
80
|
|
81
|
+
def net_amount_covered_call p
|
82
|
+
( p.begin_inner_price - p.end_inner_price )
|
83
|
+
end
|
84
|
+
def net_amount_long_debit_call_spread p
|
85
|
+
outer = p.end_outer_price - p.begin_outer_price
|
86
|
+
inner = p.begin_inner_price - p.end_inner_price
|
87
|
+
out = ( outer + inner )
|
88
|
+
end
|
89
|
+
alias_method :net_amount_short_debit_put_spread, :net_amount_long_debit_call_spread
|
90
|
+
|
76
91
|
def max_loss_covered_call p
|
77
|
-
|
92
|
+
p.begin_inner_price*10 # just suppose 10,000%
|
78
93
|
end
|
79
94
|
def max_loss_long_debit_call_spread p
|
80
|
-
out =
|
95
|
+
out = p.outer_strike - p.inner_strike
|
81
96
|
end
|
82
|
-
def max_loss_short_debit_put_spread p
|
83
|
-
out =
|
97
|
+
def max_loss_short_debit_put_spread p # different
|
98
|
+
out = p.inner_strike - p.outer_strike
|
84
99
|
end
|
85
100
|
|
86
|
-
def
|
87
|
-
|
101
|
+
def begin_delta_covered_call p
|
102
|
+
p.begin_inner_delta
|
88
103
|
end
|
89
|
-
def
|
90
|
-
|
91
|
-
inner = p.begin_inner_price - p.end_inner_price
|
92
|
-
out = ( outer + inner ) * 100
|
104
|
+
def begin_delta_long_debit_call_spread p
|
105
|
+
p.begin_outer_delta - p.begin_inner_delta
|
93
106
|
end
|
94
|
-
alias_method :
|
107
|
+
alias_method :begin_delta_short_debit_put_spread, :begin_delta_long_debit_call_spread
|
95
108
|
|
109
|
+
def end_delta_covered_call p
|
110
|
+
p.end_inner_delta
|
111
|
+
end
|
112
|
+
def end_delta_long_debit_call_spread p
|
113
|
+
p.end_outer_delta - p.end_inner_delta
|
114
|
+
end
|
115
|
+
alias_method :end_delta_short_debit_put_spread, :end_delta_long_debit_call_spread
|
96
116
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
117
|
+
|
118
|
+
|
119
|
+
##
|
120
|
+
## decisions
|
121
|
+
##
|
122
|
+
|
123
|
+
def calc_rollp_covered_call p
|
124
|
+
|
125
|
+
if ( p.expires_on.to_date - Time.now.to_date ).to_i < 1
|
126
|
+
return [ 0.99, '0 DTE, must exit' ]
|
127
|
+
end
|
128
|
+
|
129
|
+
if ( stock.last - buffer_above_water ) < p.inner_strike
|
130
|
+
return [ 0.98, "Last #{'%.2f' % stock.last} is " +
|
131
|
+
"#{'%.2f' % [p.inner_strike + buffer_above_water - stock.last]} " +
|
132
|
+
"below #{'%.2f' % [p.inner_strike + buffer_above_water]} water" ]
|
133
|
+
end
|
134
|
+
|
135
|
+
if p.end_inner_delta < threshold_delta
|
136
|
+
return [ 0.61, "Delta #{p.end_inner_delta} is lower than #{threshold_delta} threshold." ]
|
137
|
+
end
|
138
|
+
|
139
|
+
if 1 - p.end_inner_price/p.begin_inner_price > threshold_netp
|
140
|
+
return [ 0.51, "made enough #{'%.0f' % [(1 - p.end_inner_price/p.begin_inner_price )*100]}% profit" ]
|
141
|
+
end
|
142
|
+
|
143
|
+
return [ 0.33, '-' ]
|
101
144
|
end
|
102
145
|
|
146
|
+
## @TODO
|
147
|
+
def calc_rollp_long_debit_call_spread p
|
148
|
+
|
149
|
+
if ( p.expires_on.to_date - Time.now.to_date ).to_i < 1
|
150
|
+
return [ 0.99, '0 DTE, must exit' ]
|
151
|
+
end
|
152
|
+
if ( p.expires_on.to_date - Time.now.to_date ).to_i < 2
|
153
|
+
return [ 0.99, '1 DTE, must exit' ]
|
154
|
+
end
|
155
|
+
|
156
|
+
if ( stock.last - buffer_above_water ) < p.inner_strike
|
157
|
+
return [ 0.95, "Last #{'%.2f' % stock.last} is " +
|
158
|
+
"#{'%.2f' % [stock.last - p.inner_strike - buffer_above_water]} " +
|
159
|
+
"below #{'%.2f' % [p.inner_strike + buffer_above_water]} water" ]
|
160
|
+
end
|
161
|
+
|
162
|
+
if p.end_inner_delta < threshold_delta
|
163
|
+
return [ 0.79, "Delta #{p.end_inner_delta} is lower than #{threshold_delta} threshold." ]
|
164
|
+
end
|
165
|
+
|
166
|
+
if 1 - p.end_inner_price/p.begin_inner_price > threshold_netp
|
167
|
+
return [ 0.51, "made enough #{'%.0f' % [(1 - p.end_inner_price/p.begin_inner_price )*100]}% profit" ]
|
168
|
+
end
|
169
|
+
|
170
|
+
return [ 0.33, '-' ]
|
171
|
+
end
|
172
|
+
|
173
|
+
## @TODO
|
174
|
+
def calc_rollp_short_debit_put_spread p
|
175
|
+
|
176
|
+
if ( p.expires_on.to_date - Time.now.to_date ).to_i < 1
|
177
|
+
return [ 0.99, '0 DTE, must exit' ]
|
178
|
+
end
|
179
|
+
|
180
|
+
if ( stock.last - buffer_above_water ) < p.inner_strike
|
181
|
+
return [ 0.98, "Last #{'%.2f' % stock.last} is " +
|
182
|
+
"#{'%.2f' % [stock.last - p.inner_strike - buffer_above_water]} " +
|
183
|
+
"above #{'%.2f' % [p.inner_strike + buffer_above_water]} water" ]
|
184
|
+
end
|
185
|
+
|
186
|
+
if p.end_inner_delta < threshold_delta
|
187
|
+
return [ 0.79, "Delta #{p.end_inner_delta} is lower than #{threshold_delta} threshold." ]
|
188
|
+
end
|
189
|
+
|
190
|
+
if 1 - p.end_inner_price/p.begin_inner_price > threshold_netp
|
191
|
+
return [ 0.51, "made enough #{'%.0f' % [(1 - p.end_inner_price/p.begin_inner_price )*100]}% profit" ]
|
192
|
+
end
|
193
|
+
|
194
|
+
return [ 0.33, '-' ]
|
195
|
+
end
|
196
|
+
|
197
|
+
|
103
198
|
|
104
199
|
|
105
200
|
def to_s
|
106
|
-
slug
|
201
|
+
"#{stock} #{kind_short} #{slug}"
|
107
202
|
end
|
108
203
|
def self.list long_or_short = nil
|
109
204
|
these = long_or_short ? where( long_or_short: long_or_short ) : all
|
110
|
-
[[nil,nil]] + these.map { |ttt| [ ttt
|
205
|
+
[[nil,nil]] + these.map { |ttt| [ ttt, ttt.id ] }
|
111
206
|
end
|
112
207
|
end
|
data/app/models/tda/option.rb
CHANGED
@@ -68,7 +68,7 @@ class Tda::Option
|
|
68
68
|
## 2023-02-06 _vp_ :: Continue.
|
69
69
|
##
|
70
70
|
def self.get_quotes params
|
71
|
-
puts! params, 'Tda::Option#get_quotes'
|
71
|
+
# puts! params, 'Tda::Option#get_quotes'
|
72
72
|
opts = {}
|
73
73
|
|
74
74
|
#
|
@@ -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,24 +1,35 @@
|
|
1
1
|
|
2
|
-
.application-main-header.main-header
|
2
|
+
.application--main-header.main-header.iro--main-header{ class: "#{ENV['RAILS_ENV']} #{ENV['RAILS_ENV'][0...3]=="dev" ? "development" : ''}" }
|
3
3
|
.maxwidth
|
4
4
|
|
5
5
|
%i.fa.fa-compress.collapse-expand#collapseHeaderTrading
|
6
|
-
|
6
|
+
Wco Trading
|
7
|
+
.a
|
8
|
+
.d-flex
|
9
|
+
%ul{ style: "margin-top: 2em;" }
|
10
|
+
%li
|
11
|
+
= link_to "Stocks (#{Iro::Stock.all.length})", stocks_path
|
12
|
+
= link_to '[re]', refresh_stocks_path
|
13
|
+
-# %li= link_to 'Options', options_path
|
14
|
+
-# %li Max Pain
|
15
|
+
%li
|
16
|
+
= link_to "Alerts (#{Iro::Alert.all.length})", alerts_path
|
17
|
+
%li
|
18
|
+
= link_to "Purses (#{Iro::Purse.all.length})", purses_path
|
19
|
+
%li
|
20
|
+
= render '/iro/strategies/header'
|
7
21
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
= link_to "Purses (#{Iro::Purse.all.length})", purses_path
|
21
|
-
%li
|
22
|
-
= render '/iro/strategies/header'
|
22
|
+
.a
|
23
|
+
= link_to 'Purses', purses_path
|
24
|
+
%ul
|
25
|
+
- @purses.each do |p|
|
26
|
+
%li= link_to p, purse_path(p)
|
27
|
+
.a
|
28
|
+
= link_to 'Strategies', strategies_path
|
29
|
+
%ul
|
30
|
+
- @strategies.each do |s|
|
31
|
+
%li
|
32
|
+
= link_to s, strategy_path(s)
|
33
|
+
= link_to '[~]', edit_strategy_path(s)
|
23
34
|
|
24
35
|
|
@@ -7,8 +7,7 @@
|
|
7
7
|
.d-flex
|
8
8
|
.field
|
9
9
|
%label Purse
|
10
|
-
|
11
|
-
= f.text_field :purse_id
|
10
|
+
= f.select :purse_id, options_for_select( @purses_list, selected: position.purse_id )
|
12
11
|
|
13
12
|
%label Status
|
14
13
|
= f.select :status, options_for_select( Iro::Position::STATUSES, selected: position.status )
|
@@ -2,7 +2,7 @@
|
|
2
2
|
- pos = position
|
3
3
|
- stock = pos.stock
|
4
4
|
- nearest_strike = stock.last.round
|
5
|
-
- u =
|
5
|
+
- u = pos.purse.unit # pixels per dollar
|
6
6
|
|
7
7
|
.collapse-expand.d-flex{ id: "gameui-pos-#{pos.id}" }
|
8
8
|
[<>]
|
@@ -10,32 +10,29 @@
|
|
10
10
|
.a
|
11
11
|
= render "/iro/positions/header_#{pos.strategy.kind}", pos: pos
|
12
12
|
.StockCoordinatesW
|
13
|
-
.StockCoordinates{ style: "height: #{pos.
|
14
|
-
= render "/iro/stocks/grid_#{pos.strategy.long_or_short}", stock: stock
|
13
|
+
.StockCoordinates{ style: "height: #{pos.q() * u}px " }
|
14
|
+
.grid= render "/iro/stocks/grid_#{pos.strategy.long_or_short}", stock: stock, position: pos
|
15
15
|
|
16
16
|
.Origin{ style: "left: #{ ( nearest_strike - stock.last )* u}px" }
|
17
17
|
.label Last: #{pp_amount stock.last}
|
18
|
-
.c
|
19
18
|
|
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
19
|
- left = "#{ (stock.last - pos.inner_strike) * u}px"
|
24
20
|
- width = "0px"
|
25
|
-
.PositionW{ style: "left: #{left} ; width: #{width} " }
|
21
|
+
.PositionW{ class: pos.strategy.kind, style: "left: #{left} ; width: #{width} " }
|
26
22
|
.Position
|
23
|
+
.RollGuide
|
27
24
|
.PositionC
|
28
25
|
|
29
|
-
- if
|
30
|
-
.Net.NetPositive{ style: "width: #{ (
|
26
|
+
- if pos.net_amount >= 0
|
27
|
+
.Net.NetPositive{ style: "width: #{ (pos.net_amount / 100) * u }px; right: 0" }
|
31
28
|
.label
|
32
29
|
net
|
33
|
-
= pp_amount
|
30
|
+
= pp_amount pos.net_amount
|
34
31
|
- else
|
35
|
-
.Net.NetNegative{ style: "width: #{ (-1 *
|
32
|
+
.Net.NetNegative{ style: "width: #{ (-1 * pos.net_amount / 100) * u }px; left: 100%" }
|
36
33
|
.label
|
37
34
|
net
|
38
|
-
= pp_amount
|
35
|
+
= pp_amount pos.net_amount
|
39
36
|
|
40
37
|
.Breakeven{ style: "width: #{ pos.begin_inner_price * u }px" }
|
41
38
|
.label
|
@@ -1,4 +1,12 @@
|
|
1
1
|
|
2
|
+
|
3
|
+
-## Good, remove trash, leave as implemented.
|
4
|
+
-# - left = "#{ (stock.last - pos.inner_strike - pos.begin_inner_price) * u}px"
|
5
|
+
-# - width = "#{ pos.begin_inner_price * u}px"
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
|
2
10
|
- unit = u = 50 # pixels per dollar
|
3
11
|
- grid_size = 100 # dollars to each side of origin
|
4
12
|
.purses-gameui.padded
|