iron_warbler 2.0.7.25 → 2.0.7.27
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/iron_warbler/Card.scss +6 -0
- data/app/assets/stylesheets/iron_warbler/positions.scss +1 -1
- data/app/assets/stylesheets/iron_warbler/purses.scss +31 -0
- data/app/assets/stylesheets/iron_warbler/purses_summary.scss +31 -19
- data/app/assets/stylesheets/iron_warbler/utils.scss +28 -3
- data/app/controllers/iro/api/stocks_controller.rb +7 -4
- data/app/controllers/iro/application_controller.rb +6 -0
- data/app/controllers/iro/positions_controller.rb +188 -199
- data/app/controllers/iro/purses_controller.rb +3 -1
- data/app/controllers/iro/stocks_controller.rb +21 -2
- data/app/models/iro/datapoint.rb +1 -1
- data/app/models/iro/option.rb +50 -150
- data/app/models/iro/option_black_scholes.rb +149 -0
- data/app/models/iro/position.rb +155 -212
- data/app/models/iro/{price_item.rb → priceitem.rb} +5 -1
- data/app/models/iro/purse.rb +41 -4
- data/app/models/iro/stock.rb +2 -0
- data/app/models/iro/strategy.rb +121 -82
- data/app/models/tda/option.rb +1 -1
- data/app/models/tda/stock.rb +1 -1
- data/app/views/iro/_main_header.haml +8 -5
- data/app/views/iro/api/stocks/index.json.jbuilder +5 -0
- data/app/views/iro/api/stocks/show.json.jbuilder +11 -0
- data/app/views/iro/api/stocks/show.json.jbuilder-bk +12 -0
- data/app/views/iro/options/_show_mini.haml +8 -0
- data/app/views/iro/positions/_form.haml +11 -4
- data/app/views/iro/positions/_formpart_4data.haml +41 -38
- data/app/views/iro/positions/_gameui_long_debit_call_spread.haml +4 -4
- data/app/views/iro/positions/_gameui_long_debit_call_spread.haml-trash +42 -0
- data/app/views/iro/positions/_gameui_short_credit_call_spread.haml +38 -0
- data/app/views/iro/positions/_gameui_short_debit_put_spread.haml +1 -0
- data/app/views/iro/positions/_gameui_short_debit_put_spread.haml-trash +40 -0
- data/app/views/iro/positions/_header.haml +2 -0
- data/app/views/iro/positions/_header_long_debit_call_spread.haml +43 -25
- data/app/views/iro/positions/_header_short_credit_call_spread.haml +50 -0
- data/app/views/iro/positions/_new.haml +23 -0
- data/app/views/iro/positions/_prepare_long_debit_call_spread.haml +2 -3
- data/app/views/iro/positions/_prepare_short_credit_call_spread.haml +1 -0
- data/app/views/iro/positions/_prepare_short_debit_put_spread.haml +2 -1
- data/app/views/iro/positions/_table.haml +25 -26
- data/app/views/iro/positions/prepare.haml +6 -4
- data/app/views/iro/positions/prepare2.haml +15 -4
- data/app/views/iro/purses/_form_extra_fields.haml +18 -18
- data/app/views/iro/purses/_header.haml +12 -7
- data/app/views/iro/purses/_summary.haml +69 -62
- data/app/views/iro/purses/show.haml +4 -3
- data/app/views/iro/stocks/_form.haml +4 -3
- data/app/views/iro/stocks/edit.haml +4 -0
- data/app/views/iro/stocks/index.haml +21 -6
- data/app/views/iro/strategies/_form.haml +36 -26
- data/app/views/iro/strategies/_show.haml +7 -5
- data/config/routes.rb +7 -4
- data/lib/iro/engine.rb +1 -0
- data/lib/iron_warbler.rb +0 -2
- data/lib/tasks/iro_tasks.rake +2 -2
- metadata +17 -4
- data/app/views/iro/api/stocks/show.jbuilder +0 -11
- data/app/views/iro/positions/_gameui_short_debit_put_spread.haml +0 -40
data/app/models/iro/position.rb
CHANGED
@@ -5,11 +5,20 @@ class Iro::Position
|
|
5
5
|
include Mongoid::Paranoia
|
6
6
|
store_in collection: 'iro_positions'
|
7
7
|
|
8
|
+
field :prev_gain_loss_amount, type: :float
|
8
9
|
attr_accessor :next_gain_loss_amount
|
10
|
+
def prev_gain_loss_amount
|
11
|
+
out = autoprev.outer.end_price - autoprev.inner.end_price
|
12
|
+
out += inner.begin_price - outer.begin_price
|
13
|
+
end
|
14
|
+
|
9
15
|
|
10
16
|
STATUS_ACTIVE = 'active'
|
17
|
+
STATUS_CLOSED = 'closed'
|
11
18
|
STATUS_PROPOSED = 'proposed'
|
12
|
-
|
19
|
+
## one more, 'selected' after proposed?
|
20
|
+
STATUS_PENDING = 'pending' ## 'working'
|
21
|
+
STATUSES = [ nil, STATUS_CLOSED, STATUS_ACTIVE, STATUS_PROPOSED, STATUS_PENDING ]
|
13
22
|
field :status
|
14
23
|
validates :status, presence: true
|
15
24
|
scope :active, ->{ where( status: 'active' ) }
|
@@ -17,27 +26,37 @@ class Iro::Position
|
|
17
26
|
belongs_to :purse, class_name: 'Iro::Purse', inverse_of: :positions
|
18
27
|
index({ purse_id: 1, ticker: 1 })
|
19
28
|
|
20
|
-
belongs_to :prev, class_name: 'Iro::Position', inverse_of: :nxt
|
21
|
-
has_one :nxt, class_name: 'Iro::Position', inverse_of: :prev
|
22
|
-
|
23
29
|
belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :positions
|
24
|
-
|
25
|
-
stock&.ticker || '-'
|
26
|
-
end
|
30
|
+
delegate :ticker, to: :stock
|
27
31
|
|
28
32
|
belongs_to :strategy, class_name: 'Iro::Strategy', inverse_of: :positions
|
33
|
+
delegate :put_call, to: :strategy
|
34
|
+
delegate :long_or_short, to: :strategy
|
29
35
|
|
30
|
-
|
31
|
-
|
36
|
+
belongs_to :next_strategy, class_name: 'Iro::Strategy', inverse_of: :next_position, optional: true
|
37
|
+
|
38
|
+
|
39
|
+
belongs_to :prev, class_name: 'Iro::Position', inverse_of: :nxts, optional: true
|
40
|
+
belongs_to :autoprev, class_name: 'Iro::Position', inverse_of: :autonxt, optional: true
|
41
|
+
## there are many of these, for viewing on the 'roll' view
|
42
|
+
has_many :nxts, class_name: 'Iro::Position', inverse_of: :prev
|
43
|
+
has_one :autonxt, class_name: 'Iro::Position', inverse_of: :autoprev
|
44
|
+
|
45
|
+
## Options
|
32
46
|
|
33
|
-
belongs_to :outer, class_name: 'Iro::Option', inverse_of: :outer
|
34
47
|
belongs_to :inner, class_name: 'Iro::Option', inverse_of: :inner
|
48
|
+
validates_associated :inner
|
49
|
+
|
50
|
+
belongs_to :outer, class_name: 'Iro::Option', inverse_of: :outer
|
51
|
+
validates_associated :outer
|
52
|
+
|
53
|
+
accepts_nested_attributes_for :inner, :outer
|
35
54
|
|
36
55
|
field :outer_strike, type: :float
|
37
56
|
# validates :outer_strike, presence: true
|
38
57
|
|
39
58
|
field :inner_strike, type: :float
|
40
|
-
validates :inner_strike, presence: true
|
59
|
+
# validates :inner_strike, presence: true
|
41
60
|
|
42
61
|
field :expires_on
|
43
62
|
validates :expires_on, presence: true
|
@@ -47,18 +66,8 @@ class Iro::Position
|
|
47
66
|
def q; quantity; end
|
48
67
|
|
49
68
|
field :begin_on
|
50
|
-
field :begin_outer_price, type: :float
|
51
|
-
field :begin_outer_delta, type: :float
|
52
|
-
|
53
|
-
field :begin_inner_price, type: :float
|
54
|
-
field :begin_inner_delta, type: :float
|
55
69
|
|
56
70
|
field :end_on
|
57
|
-
field :end_outer_price, type: :float
|
58
|
-
field :end_outer_delta, type: :float
|
59
|
-
|
60
|
-
field :end_inner_price, type: :float
|
61
|
-
field :end_inner_delta, type: :float
|
62
71
|
|
63
72
|
def begin_delta
|
64
73
|
strategy.send("begin_delta_#{strategy.kind}", self)
|
@@ -86,7 +95,7 @@ class Iro::Position
|
|
86
95
|
end_delta: out[:delta],
|
87
96
|
end_price: out[:last],
|
88
97
|
})
|
89
|
-
print '
|
98
|
+
print '^'
|
90
99
|
end
|
91
100
|
|
92
101
|
def net_percent
|
@@ -101,237 +110,171 @@ class Iro::Position
|
|
101
110
|
def max_loss # each
|
102
111
|
strategy.send("max_loss_#{strategy.kind}", self)
|
103
112
|
end
|
104
|
-
# def gain_loss_amount
|
105
|
-
# strategy.send("gain_loss_amount_#{strategy.kind}", self)
|
106
|
-
# end
|
107
|
-
|
108
|
-
|
109
|
-
field :next_delta, type: :float
|
110
|
-
field :next_outcome, type: :float
|
111
|
-
field :next_symbol
|
112
|
-
field :next_mark
|
113
|
-
field :next_reasons, type: :array, default: []
|
114
|
-
field :rollp, type: :float
|
115
113
|
|
116
114
|
|
117
|
-
## covered call
|
118
|
-
# def sync
|
119
|
-
# puts! [ inner_strike, expires_on, stock.ticker ], 'init sync'
|
120
|
-
# out = Tda::Option.get_quote({
|
121
|
-
# contractType: 'CALL',
|
122
|
-
# strike: inner_strike,
|
123
|
-
# expirationDate: expires_on,
|
124
|
-
# ticker: stock.ticker,
|
125
|
-
# })
|
126
|
-
# puts! out, 'sync'
|
127
|
-
# self.end_inner_price = ( out.bid + out.ask ) / 2
|
128
|
-
# self.end_inner_delta = out.delta
|
129
|
-
# end
|
130
|
-
|
131
|
-
## long call spread
|
132
|
-
# def sync
|
133
|
-
# # puts! [
|
134
|
-
# # [ inner_strike, expires_on, stock.ticker ],
|
135
|
-
# # [ outer_strike, expires_on, stock.ticker ],
|
136
|
-
# # ], 'init sync inner, outer'
|
137
|
-
# inner = Tda::Option.get_quote({
|
138
|
-
# contractType: 'CALL',
|
139
|
-
# strike: inner_strike,
|
140
|
-
# expirationDate: expires_on,
|
141
|
-
# ticker: stock.ticker,
|
142
|
-
# })
|
143
|
-
# outer = Tda::Option.get_quote({
|
144
|
-
# contractType: 'CALL',
|
145
|
-
# strike: outer_strike,
|
146
|
-
# expirationDate: expires_on,
|
147
|
-
# ticker: stock.ticker,
|
148
|
-
# })
|
149
|
-
# puts! [inner, outer], 'sync inner, outer'
|
150
|
-
# self.end_outer_price = ( outer.bid + outer.ask ) / 2
|
151
|
-
# self.end_outer_delta = outer.delta
|
152
|
-
|
153
|
-
# self.end_inner_price = ( inner.bid + inner.ask ) / 2
|
154
|
-
# self.end_inner_delta = inner.delta
|
155
|
-
# end
|
156
|
-
|
157
115
|
def sync
|
158
|
-
|
159
|
-
|
160
|
-
[ inner_strike, expires_on, stock.ticker ],
|
161
|
-
[ outer_strike, expires_on, stock.ticker ],
|
162
|
-
], 'init sync inner, outer'
|
163
|
-
inner = Tda::Option.get_quote({
|
164
|
-
contractType: put_call,
|
165
|
-
strike: inner_strike,
|
166
|
-
expirationDate: expires_on,
|
167
|
-
ticker: stock.ticker,
|
168
|
-
})
|
169
|
-
outer = Tda::Option.get_quote({
|
170
|
-
contractType: put_call,
|
171
|
-
strike: outer_strike,
|
172
|
-
expirationDate: expires_on,
|
173
|
-
ticker: stock.ticker,
|
174
|
-
})
|
175
|
-
puts! [inner, outer], 'sync inner, outer'
|
176
|
-
self.end_outer_price = ( outer.bid + outer.ask ) / 2
|
177
|
-
self.end_outer_delta = outer.delta
|
178
|
-
|
179
|
-
self.end_inner_price = ( inner.bid + inner.ask ) / 2
|
180
|
-
self.end_inner_delta = inner.delta
|
116
|
+
inner.sync
|
117
|
+
outer.sync
|
181
118
|
end
|
182
|
-
def sync_short_debit_put_spread
|
183
|
-
puts! [
|
184
|
-
[ inner_strike, expires_on, stock.ticker ],
|
185
|
-
[ outer_strike, expires_on, stock.ticker ],
|
186
|
-
], 'init sync inner, outer'
|
187
|
-
inner = Tda::Option.get_quote({
|
188
|
-
contractType: 'PUT',
|
189
|
-
strike: inner_strike,
|
190
|
-
expirationDate: expires_on,
|
191
|
-
ticker: stock.ticker,
|
192
|
-
})
|
193
|
-
outer = Tda::Option.get_quote({
|
194
|
-
contractType: 'PUT',
|
195
|
-
strike: outer_strike,
|
196
|
-
expirationDate: expires_on,
|
197
|
-
ticker: stock.ticker,
|
198
|
-
})
|
199
|
-
puts! [inner, outer], 'sync inner, outer'
|
200
|
-
self.end_outer_price = ( outer.bid + outer.ask ) / 2
|
201
|
-
self.end_outer_delta = outer.delta
|
202
119
|
|
203
|
-
self.end_inner_price = ( inner.bid + inner.ask ) / 2
|
204
|
-
self.end_inner_delta = inner.delta
|
205
|
-
end
|
206
120
|
|
207
121
|
##
|
208
122
|
## decisions
|
209
123
|
##
|
210
124
|
|
125
|
+
field :next_reasons, type: :array, default: []
|
126
|
+
field :rollp, type: :float
|
127
|
+
|
128
|
+
## should_roll?
|
211
129
|
def calc_rollp
|
212
130
|
self.next_reasons = []
|
213
|
-
self.next_symbol
|
214
|
-
self.next_delta
|
131
|
+
# self.next_symbol = nil
|
132
|
+
# self.next_delta = nil
|
215
133
|
|
216
134
|
out = strategy.send( "calc_rollp_#{strategy.kind}", self )
|
217
135
|
|
218
136
|
self.rollp = out[0]
|
219
137
|
self.next_reasons.push out[1]
|
220
138
|
save
|
221
|
-
|
222
|
-
# update({
|
223
|
-
# next_delta: next_position[:delta],
|
224
|
-
# next_outcome: next_position[:mark] - end_price,
|
225
|
-
# next_symbol: next_position[:symbol],
|
226
|
-
# next_mark: next_position[:mark],
|
227
|
-
# should_rollp: out,
|
228
|
-
# # status: Iro::Position::STATE_PROPOSED,
|
229
|
-
# })
|
230
139
|
end
|
231
140
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
## only if less than 7 days left
|
236
|
-
( expires_on.to_date - Time.now.to_date ).to_i < 7
|
237
|
-
end
|
238
|
-
|
239
|
-
## strike = cc.strike ; strategy = cc.strategy ; nil
|
240
|
-
def near_below_water?
|
241
|
-
strike < current_underlying_strike + strategy.buffer_above_water
|
242
|
-
end
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
## 2023-03-18 _vp_ Continue.
|
247
|
-
## 2023-03-19 _vp_ Continue.
|
248
|
-
## 2023-08-05 _vp_ an Important method
|
249
|
-
##
|
250
|
-
## expires_on = cc.expires_on ; strategy = cc.strategy ; ticker = cc.ticker ; end_price = cc.end_price ; next_expires_on = cc.next_expires_on ; nil
|
251
|
-
##
|
252
|
-
## out.map { |p| [ p[:strikePrice], p[:delta] ] }
|
253
|
-
##
|
254
|
-
def next_position
|
255
|
-
return @next_position if @next_position
|
256
|
-
return {} if ![ STATUS_ACTIVE, STATUS_PROPOSED ].include?( status )
|
141
|
+
## @TODO: herehere 2024-05-09
|
142
|
+
def calc_nxt
|
143
|
+
pos = self
|
257
144
|
|
258
145
|
## 7 days ahead - not configurable so far
|
259
|
-
|
260
|
-
|
146
|
+
outs = Tda::Option.get_quotes({
|
147
|
+
contractType: pos.put_call,
|
261
148
|
expirationDate: next_expires_on,
|
262
|
-
|
149
|
+
ticker: ticker,
|
263
150
|
})
|
151
|
+
outs_bk = outs.dup
|
264
152
|
|
265
|
-
|
266
|
-
|
267
|
-
out = out.select do |i|
|
268
|
-
i[:strikePrice] > current_underlying_strike + strategy.buffer_above_water
|
269
|
-
end
|
270
|
-
# next_reasons.push "buffer_above_water above #{current_underlying_strike + strategy.buffer_above_water}"
|
153
|
+
outs = outs.select do |out|
|
154
|
+
out[:bidSize] + out[:askSize] > 0
|
271
155
|
end
|
272
156
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
157
|
+
## next_inner_strike
|
158
|
+
outs = outs.select do |out|
|
159
|
+
if Iro::Strategy::SHORT == pos.long_or_short
|
160
|
+
out[:strikePrice] >= strategy.next_inner_strike
|
161
|
+
elsif Iro::Strategy::LONG == pos.long_or_short
|
162
|
+
out[:strikePrice] <= strategy.next_inner_strike
|
163
|
+
else
|
164
|
+
raise 'zz3 - this cannot happen'
|
165
|
+
end
|
166
|
+
end
|
167
|
+
puts! outs[0][:strikePrice], 'after calc next_inner_strike'
|
168
|
+
|
169
|
+
## next_buffer_above_water
|
170
|
+
outs = outs.select do |out|
|
171
|
+
if Iro::Strategy::SHORT == pos.long_or_short
|
172
|
+
out[:strikePrice] > strategy.next_buffer_above_water + strategy.stock.last
|
173
|
+
elsif Iro::Strategy::LONG == pos.long_or_short
|
174
|
+
out[:strikePrice] < strategy.stock.last - strategy.next_buffer_above_water
|
175
|
+
else
|
176
|
+
raise 'zz4 - this cannot happen'
|
177
|
+
end
|
178
|
+
end
|
179
|
+
puts! outs[0][:strikePrice], 'after calc next_buffer_above_water'
|
277
180
|
|
278
|
-
|
181
|
+
## next_inner_delta
|
182
|
+
outs = outs.select do |out|
|
183
|
+
out_delta = out[:delta].abs rescue 0
|
184
|
+
out_delta >= strategy.next_inner_delta.abs
|
185
|
+
end
|
186
|
+
puts! outs[0][:strikePrice], 'after calc next_inner_delta'
|
279
187
|
|
280
|
-
|
281
|
-
|
282
|
-
out.
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
188
|
+
inner = outs[0]
|
189
|
+
outs = outs.select do |out|
|
190
|
+
out[:strikePrice] >= inner[:strikePrice].to_f + strategy.next_spread_amount
|
191
|
+
end
|
192
|
+
outer = outs[0]
|
193
|
+
|
194
|
+
if inner && outer
|
195
|
+
o_attrs = {
|
196
|
+
expires_on: next_expires_on,
|
197
|
+
put_call: pos.put_call,
|
198
|
+
stock_id: pos.stock_id,
|
199
|
+
}
|
200
|
+
inner_ = Iro::Option.new(o_attrs.merge({
|
201
|
+
strike: inner[:strikePrice],
|
202
|
+
begin_price: ( inner[:bid] + inner[:ask] )/2,
|
203
|
+
begin_delta: inner[:delta],
|
204
|
+
end_price: ( inner[:bid] + inner[:ask] )/2,
|
205
|
+
end_delta: inner[:delta],
|
206
|
+
}))
|
207
|
+
outer_ = Iro::Option.new(o_attrs.merge({
|
208
|
+
strike: outer[:strikePrice],
|
209
|
+
begin_price: ( outer[:bid] + outer[:ask] )/2,
|
210
|
+
begin_delta: outer[:delta],
|
211
|
+
end_price: ( outer[:bid] + outer[:ask] )/2,
|
212
|
+
end_delta: outer[:delta],
|
213
|
+
}))
|
214
|
+
pos.autonxt ||= Iro::Position.new
|
215
|
+
pos.autonxt.update({
|
216
|
+
prev_gain_loss_amount: 'a',
|
217
|
+
status: 'proposed',
|
218
|
+
stock: strategy.stock,
|
219
|
+
inner: inner_,
|
220
|
+
outer: outer_,
|
221
|
+
inner_strike: inner_.strike,
|
222
|
+
outer_strike: outer_.strike,
|
223
|
+
begin_on: Time.now.to_date,
|
224
|
+
expires_on: next_expires_on,
|
225
|
+
purse: purse,
|
226
|
+
strategy: strategy,
|
227
|
+
quantity: 1,
|
228
|
+
autoprev: pos,
|
229
|
+
})
|
230
|
+
|
231
|
+
pos.autonxt.sync
|
232
|
+
pos.autonxt.save!
|
233
|
+
pos.save
|
234
|
+
return pos
|
289
235
|
|
290
236
|
else
|
291
|
-
|
292
|
-
## @TODO: test! _vp_ 2023-03-19
|
293
|
-
|
294
|
-
## next_min_strike
|
295
|
-
if strategy.next_min_strike.present?
|
296
|
-
out = out.select do |i|
|
297
|
-
i[:strikePrice] >= strategy.next_min_strike
|
298
|
-
end
|
299
|
-
# next_reasons.push "next_min_strike above #{strategy.next_min_strike}"
|
300
|
-
end
|
301
|
-
# json_puts! out.map { |p| [p[:delta], p[:symbol]] }, 'next_min_strike'
|
302
|
-
|
303
|
-
## max_delta
|
304
|
-
if strategy.next_max_delta.present?
|
305
|
-
out = out.select do |i|
|
306
|
-
i[:delta] = 0.0 if i[:delta] == "NaN"
|
307
|
-
i[:delta] <= strategy.next_max_delta
|
308
|
-
end
|
309
|
-
# next_reasons.push "next_max_delta below #{strategy.next_max_delta}"
|
310
|
-
end
|
311
|
-
# json_puts! out.map { |p| [p[:delta], p[:symbol]] }, 'next_max_delta'
|
237
|
+
throw 'zmq - should not happen'
|
312
238
|
end
|
313
|
-
|
314
|
-
@next_position = out[0] || {}
|
315
239
|
end
|
316
240
|
|
317
|
-
|
241
|
+
|
242
|
+
|
243
|
+
## ok
|
318
244
|
def next_expires_on
|
319
|
-
out = expires_on.
|
320
|
-
|
321
|
-
out = out
|
322
|
-
end
|
323
|
-
while !out.workday?
|
324
|
-
out = out - 1.day
|
245
|
+
out = expires_on.to_datetime.next_occurring(:monday).next_occurring(:friday)
|
246
|
+
if !out.workday?
|
247
|
+
out = Time.previous_business_day(out)
|
325
248
|
end
|
326
249
|
return out
|
327
250
|
end
|
328
251
|
|
252
|
+
## ok
|
253
|
+
def self.long
|
254
|
+
where( long_or_short: Iro::Strategy::LONG )
|
255
|
+
end
|
256
|
+
|
257
|
+
## ok
|
258
|
+
def self.short
|
259
|
+
where( long_or_short: Iro::Strategy::SHORT )
|
260
|
+
end
|
261
|
+
|
329
262
|
def to_s
|
330
|
-
out = "#{stock} (#{q}) #{expires_on.to_datetime.strftime('%b %d')} #{strategy.
|
331
|
-
if
|
332
|
-
|
263
|
+
out = "#{stock} (#{q}) #{expires_on.to_datetime.strftime('%b %d')} #{strategy.long_or_short} ["
|
264
|
+
if Iro::Strategy::LONG == long_or_short
|
265
|
+
if outer.strike
|
266
|
+
out = out + "$#{outer.strike}->"
|
267
|
+
end
|
268
|
+
out = out + "$#{inner.strike}"
|
269
|
+
else
|
270
|
+
out = out + "$#{inner.strike}"
|
271
|
+
if outer.strike
|
272
|
+
out = out + "<-$#{outer.strike}"
|
273
|
+
end
|
333
274
|
end
|
334
|
-
out
|
275
|
+
out += "] "
|
335
276
|
return out
|
336
277
|
end
|
337
278
|
end
|
279
|
+
|
280
|
+
|
@@ -1,5 +1,8 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
##
|
3
|
+
## specifically Option or Stock priceitem?
|
4
|
+
##
|
5
|
+
class Iro::Priceitem
|
3
6
|
include Mongoid::Document
|
4
7
|
include Mongoid::Timestamps
|
5
8
|
store_in collection: 'iro_price_items'
|
@@ -8,6 +11,7 @@ class Iro::PriceItem
|
|
8
11
|
field :putCall, type: String
|
9
12
|
field :symbol, type: String
|
10
13
|
field :ticker, type: String
|
14
|
+
# belongs_to :stock, inverse_of: :priceitems
|
11
15
|
|
12
16
|
field :bid, type: Float
|
13
17
|
field :bidSize, type: Integer
|
data/app/models/iro/purse.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
|
2
|
+
require 'distribution'
|
3
|
+
N = Distribution::Normal
|
4
|
+
|
2
5
|
class Iro::Purse
|
3
6
|
include Mongoid::Document
|
4
7
|
include Mongoid::Timestamps
|
@@ -9,22 +12,56 @@ class Iro::Purse
|
|
9
12
|
validates :slug, presence: true, uniqueness: true
|
10
13
|
index({ slug: -1 }, { unique: true })
|
11
14
|
|
12
|
-
has_many :positions,
|
15
|
+
has_many :positions, class_name: 'Iro::Position', inverse_of: :purse
|
16
|
+
|
17
|
+
has_and_belongs_to_many :strategies, class_name: 'Iro::Strategy', inverse_of: :purses
|
13
18
|
|
14
19
|
belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :strategies
|
15
20
|
|
16
21
|
field :unit, type: :integer, default: 10
|
22
|
+
## with unit 10, .001
|
23
|
+
## with unit 100, .0001
|
24
|
+
field :summary_unit, type: :float, default: 0.001
|
17
25
|
|
18
26
|
## for rolling only:
|
19
27
|
field :height, type: :integer, default: 100
|
20
28
|
|
21
29
|
field :mark_every_n_usd, type: :float, default: 1
|
22
30
|
field :n_next_positions, type: :integer, default: 5
|
23
|
-
## with unit 10, sum_scale .001
|
24
|
-
## with unit 100, sum_scale .0001
|
25
|
-
field :summary_scale, type: :float, default: 0.001
|
26
31
|
|
27
32
|
field :available_amount, type: :float
|
33
|
+
def available
|
34
|
+
available_amount
|
35
|
+
end
|
36
|
+
|
37
|
+
def balance
|
38
|
+
0.01
|
39
|
+
end
|
40
|
+
|
41
|
+
def delta_wt_avg( begin_end, long_short, inner_outer )
|
42
|
+
max_loss_total = 0
|
43
|
+
|
44
|
+
out = positions.send( long_short ).map do |pos|
|
45
|
+
max_loss_total += pos.max_loss * pos.q
|
46
|
+
pos.max_loss * pos.q * pos.send( inner_outer ).send( "#{begin_end}_delta" )
|
47
|
+
end
|
48
|
+
# puts! out, 'delta_wt_avg 1'
|
49
|
+
out = out.reduce( &:+ ) / max_loss_total rescue 0
|
50
|
+
# puts! out, 'delta_wt_avg 2'
|
51
|
+
return out
|
52
|
+
end
|
53
|
+
## delta to plot percentage
|
54
|
+
## convert to normal between 0 and 3 std
|
55
|
+
def delta_to_plot_p( *args )
|
56
|
+
x = delta_wt_avg( *args ).abs
|
57
|
+
if x < 0.5
|
58
|
+
y = 1
|
59
|
+
else
|
60
|
+
y = 2 - 1/( 1.5 - x )
|
61
|
+
end
|
62
|
+
y_ = "#{ (y*100) .to_i}%"
|
63
|
+
return y_
|
64
|
+
end
|
28
65
|
|
29
66
|
def to_s
|
30
67
|
slug
|
data/app/models/iro/stock.rb
CHANGED
@@ -28,7 +28,9 @@ class Iro::Stock
|
|
28
28
|
has_many :strategies, class_name: 'Iro::Strategy', inverse_of: :stock
|
29
29
|
has_many :purses, class_name: 'Iro::Purse', inverse_of: :stock
|
30
30
|
has_many :options, class_name: 'Iro::Option', inverse_of: :stock
|
31
|
+
has_many :priceitems, inverse_of: :stock
|
31
32
|
|
33
|
+
## my_find
|
32
34
|
def self.f ticker
|
33
35
|
self.find_by ticker: ticker
|
34
36
|
end
|