iron_warbler 2.0.7.24 → 2.0.7.26
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/Card.scss +6 -0
- data/app/assets/stylesheets/iron_warbler/positions.scss +1 -1
- data/app/assets/stylesheets/iron_warbler/positions_gameui.scss +8 -0
- data/app/assets/stylesheets/iron_warbler/purses_gameui.scss +2 -4
- data/app/assets/stylesheets/iron_warbler/purses_summary.scss +31 -19
- data/app/controllers/iro/application_controller.rb +6 -0
- data/app/controllers/iro/positions_controller.rb +186 -137
- data/app/controllers/iro/purses_controller.rb +3 -1
- data/app/controllers/iro/stocks_controller.rb +2 -2
- data/app/models/iro/option.rb +41 -148
- data/app/models/iro/option_black_scholes.rb +149 -0
- data/app/models/iro/position.rb +156 -205
- data/app/models/iro/purse.rb +34 -4
- data/app/models/iro/strategy.rb +49 -47
- data/app/views/iro/_main_header.haml +4 -2
- data/app/views/iro/options/_show_mini.haml +8 -0
- data/app/views/iro/positions/_form.haml +8 -3
- data/app/views/iro/positions/_formpart_4data.haml +41 -38
- data/app/views/iro/positions/_gameui_covered_call.haml +1 -1
- data/app/views/iro/positions/_gameui_long_debit_call_spread.haml +5 -5
- data/app/views/iro/positions/_gameui_long_debit_call_spread.haml-trash +42 -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/_prepare_long_debit_call_spread.haml +6 -5
- 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 +22 -0
- data/app/views/iro/purses/_form_extra_fields.haml +8 -4
- data/app/views/iro/purses/_header.haml +19 -5
- data/app/views/iro/purses/_summary.haml +69 -62
- data/app/views/iro/purses/show.haml +1 -1
- data/app/views/iro/strategies/_form.haml +26 -19
- data/app/views/iro/strategies/_show.haml +6 -4
- data/config/routes.rb +10 -7
- metadata +8 -2
- data/app/views/iro/positions/_gameui_short_debit_put_spread.haml +0 -40
data/app/models/iro/position.rb
CHANGED
@@ -5,11 +5,18 @@ 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
|
9
14
|
|
10
15
|
STATUS_ACTIVE = 'active'
|
11
16
|
STATUS_PROPOSED = 'proposed'
|
12
|
-
|
17
|
+
STATUS_CLOSED = 'closed'
|
18
|
+
STATUS_PENDING = 'pending'
|
19
|
+
STATUSES = [ nil, STATUS_ACTIVE, STATUS_PROPOSED, STATUS_CLOSED, STATUS_PENDING ]
|
13
20
|
field :status
|
14
21
|
validates :status, presence: true
|
15
22
|
scope :active, ->{ where( status: 'active' ) }
|
@@ -18,20 +25,39 @@ class Iro::Position
|
|
18
25
|
index({ purse_id: 1, ticker: 1 })
|
19
26
|
|
20
27
|
belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :positions
|
21
|
-
|
22
|
-
stock&.ticker || '-'
|
23
|
-
end
|
28
|
+
delegate :ticker, to: :stock
|
24
29
|
|
25
30
|
belongs_to :strategy, class_name: 'Iro::Strategy', inverse_of: :positions
|
31
|
+
field :long_or_short
|
32
|
+
|
33
|
+
def put_call
|
34
|
+
case strategy.kind
|
35
|
+
when Iro::Strategy::KIND_LONG_DEBIT_CALL_SPREAD
|
36
|
+
put_call = 'CALL'
|
37
|
+
when Iro::Strategy::KIND_SHORT_DEBIT_PUT_SPREAD
|
38
|
+
put_call = 'PUT'
|
39
|
+
when Iro::Strategy::KIND_COVERED_CALL
|
40
|
+
put_call = 'CALL'
|
41
|
+
end
|
42
|
+
end
|
26
43
|
|
27
|
-
|
28
|
-
|
44
|
+
belongs_to :prev, class_name: 'Iro::Position', inverse_of: :nxt, optional: true
|
45
|
+
belongs_to :autoprev, class_name: 'Iro::Position', inverse_of: :autonxt, optional: true
|
46
|
+
## there are many of these, for viewing on the 'roll' view
|
47
|
+
has_many :nxt, class_name: 'Iro::Position', inverse_of: :prev
|
48
|
+
has_one :autonxt, class_name: 'Iro::Position', inverse_of: :autoprev
|
49
|
+
|
50
|
+
## Options
|
51
|
+
|
52
|
+
belongs_to :inner, class_name: 'Iro::Option', inverse_of: :inner
|
53
|
+
belongs_to :outer, class_name: 'Iro::Option', inverse_of: :outer
|
54
|
+
accepts_nested_attributes_for :inner, :outer
|
29
55
|
|
30
56
|
field :outer_strike, type: :float
|
31
57
|
# validates :outer_strike, presence: true
|
32
58
|
|
33
59
|
field :inner_strike, type: :float
|
34
|
-
validates :inner_strike, presence: true
|
60
|
+
# validates :inner_strike, presence: true
|
35
61
|
|
36
62
|
field :expires_on
|
37
63
|
validates :expires_on, presence: true
|
@@ -41,18 +67,8 @@ class Iro::Position
|
|
41
67
|
def q; quantity; end
|
42
68
|
|
43
69
|
field :begin_on
|
44
|
-
field :begin_outer_price, type: :float
|
45
|
-
field :begin_outer_delta, type: :float
|
46
|
-
|
47
|
-
field :begin_inner_price, type: :float
|
48
|
-
field :begin_inner_delta, type: :float
|
49
70
|
|
50
71
|
field :end_on
|
51
|
-
field :end_outer_price, type: :float
|
52
|
-
field :end_outer_delta, type: :float
|
53
|
-
|
54
|
-
field :end_inner_price, type: :float
|
55
|
-
field :end_inner_delta, type: :float
|
56
72
|
|
57
73
|
def begin_delta
|
58
74
|
strategy.send("begin_delta_#{strategy.kind}", self)
|
@@ -80,7 +96,7 @@ class Iro::Position
|
|
80
96
|
end_delta: out[:delta],
|
81
97
|
end_price: out[:last],
|
82
98
|
})
|
83
|
-
print '
|
99
|
+
print '^'
|
84
100
|
end
|
85
101
|
|
86
102
|
def net_percent
|
@@ -95,237 +111,172 @@ class Iro::Position
|
|
95
111
|
def max_loss # each
|
96
112
|
strategy.send("max_loss_#{strategy.kind}", self)
|
97
113
|
end
|
98
|
-
# def gain_loss_amount
|
99
|
-
# strategy.send("gain_loss_amount_#{strategy.kind}", self)
|
100
|
-
# end
|
101
114
|
|
102
115
|
|
103
|
-
field :next_delta, type: :float
|
104
|
-
field :next_outcome, type: :float
|
105
|
-
field :next_symbol
|
106
|
-
field :next_mark
|
107
|
-
field :next_reasons, type: :array, default: []
|
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
116
|
def sync
|
152
|
-
|
153
|
-
|
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,
|
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
|
172
|
-
|
173
|
-
self.end_inner_price = ( inner.bid + inner.ask ) / 2
|
174
|
-
self.end_inner_delta = inner.delta
|
117
|
+
inner.sync
|
118
|
+
outer.sync
|
175
119
|
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
|
196
120
|
|
197
|
-
self.end_inner_price = ( inner.bid + inner.ask ) / 2
|
198
|
-
self.end_inner_delta = inner.delta
|
199
|
-
end
|
200
121
|
|
201
122
|
##
|
202
123
|
## decisions
|
203
124
|
##
|
204
125
|
|
126
|
+
field :next_reasons, type: :array, default: []
|
127
|
+
field :rollp, type: :float
|
128
|
+
|
129
|
+
## should_roll?
|
205
130
|
def calc_rollp
|
206
131
|
self.next_reasons = []
|
207
|
-
self.next_symbol
|
208
|
-
self.next_delta
|
132
|
+
# self.next_symbol = nil
|
133
|
+
# self.next_delta = nil
|
209
134
|
|
210
135
|
out = strategy.send( "calc_rollp_#{strategy.kind}", self )
|
211
136
|
|
212
137
|
self.rollp = out[0]
|
213
138
|
self.next_reasons.push out[1]
|
214
139
|
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
|
-
# })
|
224
|
-
end
|
225
|
-
|
226
|
-
|
227
|
-
## expires_on = cc.expires_on ; nil
|
228
|
-
def can_roll?
|
229
|
-
## only if less than 7 days left
|
230
|
-
( expires_on.to_date - Time.now.to_date ).to_i < 7
|
231
|
-
end
|
232
|
-
|
233
|
-
## strike = cc.strike ; strategy = cc.strategy ; nil
|
234
|
-
def near_below_water?
|
235
|
-
strike < current_underlying_strike + strategy.buffer_above_water
|
236
140
|
end
|
237
141
|
|
238
|
-
|
239
|
-
|
240
|
-
## 2023-03-18 _vp_ Continue.
|
241
|
-
## 2023-03-19 _vp_ Continue.
|
242
|
-
## 2023-08-05 _vp_ an Important method
|
243
|
-
##
|
244
|
-
## expires_on = cc.expires_on ; strategy = cc.strategy ; ticker = cc.ticker ; end_price = cc.end_price ; next_expires_on = cc.next_expires_on ; nil
|
245
|
-
##
|
246
|
-
## out.map { |p| [ p[:strikePrice], p[:delta] ] }
|
247
|
-
##
|
248
|
-
def next_position
|
249
|
-
return @next_position if @next_position
|
250
|
-
return {} if ![ STATUS_ACTIVE, STATUS_PROPOSED ].include?( status )
|
142
|
+
def calc_nxt
|
143
|
+
pos = self
|
251
144
|
|
252
145
|
## 7 days ahead - not configurable so far
|
253
|
-
|
254
|
-
|
146
|
+
outs = Tda::Option.get_quotes({
|
147
|
+
contractType: pos.put_call,
|
255
148
|
expirationDate: next_expires_on,
|
256
|
-
|
149
|
+
ticker: ticker,
|
257
150
|
})
|
151
|
+
outs_bk = outs.dup
|
258
152
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
153
|
+
# byebug
|
154
|
+
|
155
|
+
## strike price
|
156
|
+
outs = outs.select do |out|
|
157
|
+
out[:bidSize]+out[:askSize] > 0
|
158
|
+
end
|
159
|
+
outs = outs.select do |out|
|
160
|
+
if Iro::Strategy::SHORT == pos.long_or_short
|
161
|
+
out[:strikePrice] > strategy.next_buffer_above_water + strategy.stock.last
|
162
|
+
elsif Iro::Strategy::LONG == pos.long_or_short
|
163
|
+
out[:strikePrice] < strategy.stock.last - strategy.next_buffer_above_water
|
164
|
+
else
|
165
|
+
throw 'zz4 - this cannot happen'
|
166
|
+
end
|
167
|
+
end
|
168
|
+
puts! outs[0][:strikePrice], 'after calc next_buffer_above_water'
|
169
|
+
|
170
|
+
outs = outs.select do |out|
|
171
|
+
if Iro::Strategy::SHORT == pos.long_or_short
|
172
|
+
out[:strikePrice] > strategy.next_inner_strike
|
173
|
+
elsif Iro::Strategy::LONG == pos.long_or_short
|
174
|
+
out[:strikePrice] < strategy.next_inner_strike
|
175
|
+
else
|
176
|
+
throw 'zz3 - this cannot happen'
|
263
177
|
end
|
264
|
-
# next_reasons.push "buffer_above_water above #{current_underlying_strike + strategy.buffer_above_water}"
|
265
178
|
end
|
179
|
+
puts! outs[0][:strikePrice], 'after calc next_inner_strike'
|
266
180
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
181
|
+
## 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'
|
187
|
+
|
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
|
+
# byebug
|
195
|
+
|
196
|
+
if inner && outer
|
197
|
+
o_attrs = {
|
198
|
+
expires_on: next_expires_on,
|
199
|
+
put_call: pos.put_call,
|
200
|
+
stock_id: pos.stock_id,
|
201
|
+
}
|
202
|
+
inner_ = Iro::Option.new(o_attrs.merge({
|
203
|
+
strike: inner[:strikePrice],
|
204
|
+
begin_price: ( inner[:bid] + inner[:ask] )/2,
|
205
|
+
begin_delta: inner[:delta],
|
206
|
+
end_price: ( inner[:bid] + inner[:ask] )/2,
|
207
|
+
end_delta: inner[:delta],
|
208
|
+
}))
|
209
|
+
outer_ = Iro::Option.new(o_attrs.merge({
|
210
|
+
strike: outer[:strikePrice],
|
211
|
+
begin_price: ( outer[:bid] + outer[:ask] )/2,
|
212
|
+
begin_delta: outer[:delta],
|
213
|
+
end_price: ( outer[:bid] + outer[:ask] )/2,
|
214
|
+
end_delta: outer[:delta],
|
215
|
+
}))
|
216
|
+
pos.autonxt ||= Iro::Position.new
|
217
|
+
pos.autonxt.update({
|
218
|
+
prev_gain_loss_amount: 'a',
|
219
|
+
status: 'proposed',
|
220
|
+
stock: strategy.stock,
|
221
|
+
inner: inner_,
|
222
|
+
outer: outer_,
|
223
|
+
inner_strike: inner_.strike,
|
224
|
+
outer_strike: outer_.strike,
|
225
|
+
begin_on: Time.now.to_date,
|
226
|
+
expires_on: next_expires_on,
|
227
|
+
purse: purse,
|
228
|
+
strategy: strategy,
|
229
|
+
quantity: 1,
|
230
|
+
autoprev: pos,
|
231
|
+
})
|
271
232
|
|
272
233
|
# byebug
|
273
234
|
|
274
|
-
|
275
|
-
|
276
|
-
out.each_with_index do |i, idx|
|
277
|
-
next if idx == 0
|
278
|
-
if i[:last] < end_price
|
279
|
-
prev ||= i
|
280
|
-
end
|
281
|
-
end
|
282
|
-
out = [ prev ]
|
235
|
+
autonxt.sync
|
236
|
+
autonxt.save!
|
283
237
|
|
284
238
|
else
|
285
|
-
|
286
|
-
## @TODO: test! _vp_ 2023-03-19
|
287
|
-
|
288
|
-
## next_min_strike
|
289
|
-
if strategy.next_min_strike.present?
|
290
|
-
out = out.select do |i|
|
291
|
-
i[:strikePrice] >= strategy.next_min_strike
|
292
|
-
end
|
293
|
-
# next_reasons.push "next_min_strike above #{strategy.next_min_strike}"
|
294
|
-
end
|
295
|
-
# json_puts! out.map { |p| [p[:delta], p[:symbol]] }, 'next_min_strike'
|
296
|
-
|
297
|
-
## max_delta
|
298
|
-
if strategy.next_max_delta.present?
|
299
|
-
out = out.select do |i|
|
300
|
-
i[:delta] = 0.0 if i[:delta] == "NaN"
|
301
|
-
i[:delta] <= strategy.next_max_delta
|
302
|
-
end
|
303
|
-
# next_reasons.push "next_max_delta below #{strategy.next_max_delta}"
|
304
|
-
end
|
305
|
-
# json_puts! out.map { |p| [p[:delta], p[:symbol]] }, 'next_max_delta'
|
239
|
+
throw 'zmq - should not happen'
|
306
240
|
end
|
307
|
-
|
308
|
-
@next_position = out[0] || {}
|
309
241
|
end
|
310
242
|
|
311
|
-
|
243
|
+
|
244
|
+
|
245
|
+
## ok
|
312
246
|
def next_expires_on
|
313
|
-
out = expires_on.
|
314
|
-
|
315
|
-
out = out
|
316
|
-
end
|
317
|
-
while !out.workday?
|
318
|
-
out = out - 1.day
|
247
|
+
out = expires_on.to_datetime.next_occurring(:monday).next_occurring(:friday)
|
248
|
+
if !out.workday?
|
249
|
+
out = Time.previous_business_day(out )
|
319
250
|
end
|
320
251
|
return out
|
321
252
|
end
|
322
253
|
|
254
|
+
## ok
|
255
|
+
def self.long
|
256
|
+
where( long_or_short: Iro::Strategy::LONG )
|
257
|
+
end
|
258
|
+
|
259
|
+
## ok
|
260
|
+
def self.short
|
261
|
+
where( long_or_short: Iro::Strategy::SHORT )
|
262
|
+
end
|
263
|
+
|
323
264
|
def to_s
|
324
265
|
out = "#{stock} (#{q}) #{expires_on.to_datetime.strftime('%b %d')} #{strategy.kind_short} ["
|
325
|
-
if
|
326
|
-
|
266
|
+
if Iro::Strategy::LONG == long_or_short
|
267
|
+
if outer.strike
|
268
|
+
out = out + "$#{outer.strike}->"
|
269
|
+
end
|
270
|
+
out = out + "$#{inner.strike}"
|
271
|
+
else
|
272
|
+
out = out + "$#{inner.strike}"
|
273
|
+
if outer.strike
|
274
|
+
out = out + "<-$#{outer.strike}"
|
275
|
+
end
|
327
276
|
end
|
328
|
-
out
|
277
|
+
out += "] "
|
329
278
|
return out
|
330
279
|
end
|
331
280
|
end
|
281
|
+
|
282
|
+
|
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,23 +12,50 @@ 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
|
28
33
|
|
34
|
+
def delta_wt_avg( begin_end, long_short, inner_outer )
|
35
|
+
max_loss_total = 0
|
36
|
+
|
37
|
+
out = positions.send( long_short ).map do |pos|
|
38
|
+
max_loss_total += pos.max_loss * pos.q
|
39
|
+
pos.max_loss * pos.q * pos.send( inner_outer ).send( "#{begin_end}_delta" )
|
40
|
+
end
|
41
|
+
puts! out, 'delta_wt_avg 1'
|
42
|
+
out = out.reduce( &:+ ) / max_loss_total rescue 0
|
43
|
+
puts! out, 'delta_wt_avg 2'
|
44
|
+
return out
|
45
|
+
end
|
46
|
+
## delta to plot percentage
|
47
|
+
## convert to normal between 0 and 3 std
|
48
|
+
def delta_to_plot_p( *args )
|
49
|
+
x = delta_wt_avg( *args ).abs
|
50
|
+
if x < 0.5
|
51
|
+
y = 1
|
52
|
+
else
|
53
|
+
y = 2 - 1/( 1.5 - x )
|
54
|
+
end
|
55
|
+
y_ = "#{ (y*100) .to_i}%"
|
56
|
+
return y_
|
57
|
+
end
|
58
|
+
|
29
59
|
def to_s
|
30
60
|
slug
|
31
61
|
end
|