iron_warbler 2.0.7.43 → 2.0.7.45
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/utils.scss +9 -9
- data/app/controllers/iro/positions_controller.rb +1 -0
- data/app/controllers/iro/purses_controller.rb +3 -1
- data/app/controllers/iro/strategies_controller.rb +8 -3
- data/app/views/iro/positions/_form.haml +1 -1
- data/app/views/iro/positions/{_gameui_long_debit_call_spread.haml-trash → _gameui_spread.haml} +9 -8
- data/app/views/iro/positions/_header_spread.haml +12 -0
- data/app/views/iro/positions/_new.haml +4 -0
- data/app/views/iro/positions/done/_gameui_short_debit_put_spread.haml +1 -0
- data/app/views/iro/positions/done/_header_short_debit_put_spread.haml +1 -0
- data/app/views/iro/purses/_form.haml +3 -3
- data/app/views/iro/purses/index.haml +3 -2
- data/app/views/iro/strategies/_form_spread.haml +69 -0
- data/app/views/iro/strategies/{_form.haml → _form_wheel.haml} +12 -12
- data/app/views/iro/strategies/_header.haml +2 -1
- data/app/views/iro/strategies/_table.haml +3 -5
- data/app/views/iro/strategies/edit.haml +1 -1
- data/app/views/iro/strategies/index.haml +2 -1
- data/app/views/iro/strategies/new.haml +1 -1
- data/app/views/layouts/iro/application.haml +1 -1
- data/config/routes.rb +2 -0
- data/lib/iron_warbler.rb +2 -1
- data/lib/tasks/iro_tasks.rake +6 -0
- metadata +20 -30
- data/app/models/iro/alert.rb +0 -63
- data/app/models/iro/datapoint.rb +0 -187
- data/app/models/iro/date.rb +0 -10
- data/app/models/iro/option.rb +0 -151
- data/app/models/iro/option_black_scholes.rb +0 -149
- data/app/models/iro/position.rb +0 -299
- data/app/models/iro/priceitem.rb +0 -93
- data/app/models/iro/purse.rb +0 -72
- data/app/models/iro/stock.rb +0 -134
- data/app/models/iro/strategy.rb +0 -264
- data/app/views/iro/positions/_gameui_short_debit_put_spread.haml +0 -1
- data/app/views/iro/positions/_gameui_short_debit_put_spread.haml-trash +0 -40
- data/app/views/iro/positions/_header_short_debit_put_spread.haml +0 -1
- data/app/views/iro/positions/roll.haml-trash +0 -42
- /data/app/views/iro/positions/{_gameui_covered_call.haml-bk → done/_gameui_covered_call.haml-bk} +0 -0
- /data/app/views/iro/positions/{_gameui_long_credit_put_spread.haml → done/_gameui_long_credit_put_spread.haml} +0 -0
- /data/app/views/iro/positions/{_gameui_long_debit_call_spread.haml → done/_gameui_long_debit_call_spread.haml} +0 -0
- /data/app/views/iro/positions/{_gameui_short_credit_call_spread.haml → done/_gameui_short_credit_call_spread.haml} +0 -0
- /data/app/views/iro/positions/{_header_long_credit_put_spread.haml → done/_header_long_credit_put_spread.haml} +0 -0
- /data/app/views/iro/positions/{_header_long_debit_call_spread.haml → done/_header_long_debit_call_spread.haml} +0 -0
- /data/app/views/iro/positions/{_header_short_credit_call_spread.haml → done/_header_short_credit_call_spread.haml} +0 -0
- /data/app/views/iro/positions/{roll-cc.haml-bk → done/roll-cc.haml-bk} +0 -0
- /data/app/views/iro/purses/{gameui.haml-bk → done/gameui.haml-bk} +0 -0
- /data/app/views/iro/purses/{gameui.haml-bk2 → done/gameui.haml-bk2} +0 -0
- /data/app/views/iro/stocks/{_grid_is_long.haml → _grid_long.haml} +0 -0
- /data/app/views/iro/stocks/{_grid_is_short.haml → _grid_short.haml} +0 -0
data/app/models/iro/position.rb
DELETED
@@ -1,299 +0,0 @@
|
|
1
|
-
|
2
|
-
class Iro::Position
|
3
|
-
include Mongoid::Document
|
4
|
-
include Mongoid::Timestamps
|
5
|
-
include Mongoid::Paranoia
|
6
|
-
store_in collection: 'iro_positions'
|
7
|
-
|
8
|
-
field :prev_gain_loss_amount, type: :float
|
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
|
-
|
15
|
-
|
16
|
-
STATUS_ACTIVE = 'active'
|
17
|
-
STATUS_CLOSED = 'closed'
|
18
|
-
STATUS_PROPOSED = 'proposed'
|
19
|
-
## one more, 'selected' after proposed?
|
20
|
-
STATUS_PENDING = 'pending' ## 'working'
|
21
|
-
STATUSES = [ nil, STATUS_CLOSED, STATUS_ACTIVE, STATUS_PROPOSED, STATUS_PENDING ]
|
22
|
-
field :status
|
23
|
-
validates :status, presence: true
|
24
|
-
scope :active, ->{ where( status: 'active' ) }
|
25
|
-
|
26
|
-
belongs_to :purse, class_name: 'Iro::Purse', inverse_of: :positions
|
27
|
-
index({ purse_id: 1, ticker: 1 })
|
28
|
-
|
29
|
-
belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :positions
|
30
|
-
delegate :ticker, to: :stock
|
31
|
-
|
32
|
-
belongs_to :strategy, class_name: 'Iro::Strategy', inverse_of: :positions
|
33
|
-
delegate :put_call, to: :strategy
|
34
|
-
delegate :long_or_short, to: :strategy
|
35
|
-
|
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
|
46
|
-
|
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
|
54
|
-
|
55
|
-
field :outer_strike, type: :float
|
56
|
-
# validates :outer_strike, presence: true
|
57
|
-
|
58
|
-
field :inner_strike, type: :float
|
59
|
-
# validates :inner_strike, presence: true
|
60
|
-
|
61
|
-
field :expires_on
|
62
|
-
validates :expires_on, presence: true
|
63
|
-
|
64
|
-
field :quantity, type: :integer
|
65
|
-
validates :quantity, presence: true
|
66
|
-
def q; quantity; end
|
67
|
-
|
68
|
-
field :begin_on
|
69
|
-
|
70
|
-
field :end_on
|
71
|
-
|
72
|
-
def begin_delta
|
73
|
-
strategy.send("begin_delta_#{strategy.kind}", self)
|
74
|
-
end
|
75
|
-
def end_delta
|
76
|
-
strategy.send("end_delta_#{strategy.kind}", self)
|
77
|
-
end
|
78
|
-
|
79
|
-
def breakeven
|
80
|
-
strategy.send("breakeven_#{strategy.kind}", self)
|
81
|
-
end
|
82
|
-
|
83
|
-
def current_underlying_strike
|
84
|
-
Iro::Stock.find_by( ticker: ticker ).last
|
85
|
-
end
|
86
|
-
|
87
|
-
def refresh
|
88
|
-
out = Tda::Option.get_quote({
|
89
|
-
contractType: 'CALL',
|
90
|
-
strike: strike,
|
91
|
-
expirationDate: expires_on,
|
92
|
-
ticker: ticker,
|
93
|
-
})
|
94
|
-
update({
|
95
|
-
end_delta: out[:delta],
|
96
|
-
end_price: out[:last],
|
97
|
-
})
|
98
|
-
print '^'
|
99
|
-
end
|
100
|
-
|
101
|
-
def net_percent
|
102
|
-
net_amount / max_gain
|
103
|
-
end
|
104
|
-
def net_amount # each
|
105
|
-
strategy.send("net_amount_#{strategy.kind}", self)
|
106
|
-
end
|
107
|
-
def max_gain # each
|
108
|
-
strategy.send("max_gain_#{strategy.kind}", self)
|
109
|
-
end
|
110
|
-
def max_loss # each
|
111
|
-
strategy.send("max_loss_#{strategy.kind}", self)
|
112
|
-
end
|
113
|
-
|
114
|
-
|
115
|
-
def sync
|
116
|
-
inner.sync
|
117
|
-
outer.sync
|
118
|
-
end
|
119
|
-
|
120
|
-
|
121
|
-
##
|
122
|
-
## decisions
|
123
|
-
##
|
124
|
-
|
125
|
-
field :next_reasons, type: :array, default: []
|
126
|
-
field :rollp, type: :float
|
127
|
-
|
128
|
-
## should_roll?
|
129
|
-
def calc_rollp
|
130
|
-
self.next_reasons = []
|
131
|
-
# self.next_symbol = nil
|
132
|
-
# self.next_delta = nil
|
133
|
-
|
134
|
-
out = strategy.send( "calc_rollp_#{strategy.kind}", self )
|
135
|
-
|
136
|
-
self.rollp = out[0]
|
137
|
-
self.next_reasons.push out[1]
|
138
|
-
save
|
139
|
-
end
|
140
|
-
|
141
|
-
def calc_nxt
|
142
|
-
pos = self
|
143
|
-
|
144
|
-
## 7 days ahead - not configurable so far
|
145
|
-
outs = Tda::Option.get_quotes({
|
146
|
-
contractType: pos.put_call,
|
147
|
-
expirationDate: next_expires_on,
|
148
|
-
ticker: ticker,
|
149
|
-
})
|
150
|
-
outs_bk = outs.dup
|
151
|
-
|
152
|
-
outs = outs.select do |out|
|
153
|
-
out[:bidSize] + out[:askSize] > 0
|
154
|
-
end
|
155
|
-
|
156
|
-
if 'CALL' == pos.put_call
|
157
|
-
;
|
158
|
-
elsif 'PUT' == pos.put_call
|
159
|
-
outs = outs.reverse
|
160
|
-
end
|
161
|
-
|
162
|
-
## next_inner_strike
|
163
|
-
outs = outs.select do |out|
|
164
|
-
if Iro::Strategy::SHORT == pos.long_or_short
|
165
|
-
out[:strikePrice] >= strategy.next_inner_strike
|
166
|
-
elsif Iro::Strategy::LONG == pos.long_or_short
|
167
|
-
out[:strikePrice] <= strategy.next_inner_strike
|
168
|
-
else
|
169
|
-
raise 'zz3 - this cannot happen'
|
170
|
-
end
|
171
|
-
end
|
172
|
-
puts! outs[0][:strikePrice], 'after calc next_inner_strike'
|
173
|
-
puts! outs, 'outs'
|
174
|
-
|
175
|
-
## next_buffer_above_water
|
176
|
-
outs = outs.select do |out|
|
177
|
-
if Iro::Strategy::SHORT == pos.long_or_short
|
178
|
-
out[:strikePrice] > strategy.next_buffer_above_water + strategy.stock.last
|
179
|
-
elsif Iro::Strategy::LONG == pos.long_or_short
|
180
|
-
out[:strikePrice] < strategy.stock.last - strategy.next_buffer_above_water
|
181
|
-
else
|
182
|
-
raise 'zz4 - this cannot happen'
|
183
|
-
end
|
184
|
-
end
|
185
|
-
puts! outs[0][:strikePrice], 'after calc next_buffer_above_water'
|
186
|
-
puts! outs, 'outs'
|
187
|
-
|
188
|
-
## next_inner_delta
|
189
|
-
outs = outs.select do |out|
|
190
|
-
if 'CALL' == pos.put_call
|
191
|
-
out_delta = out[:delta] rescue 1
|
192
|
-
out_delta <= strategy.next_inner_delta
|
193
|
-
elsif 'PUT' == pos.put_call
|
194
|
-
out_delta = out[:delta] rescue 0
|
195
|
-
out_delta <= strategy.next_inner_delta
|
196
|
-
else
|
197
|
-
raise 'zz5 - this cannot happen'
|
198
|
-
end
|
199
|
-
end
|
200
|
-
puts! outs[0][:strikePrice], 'after calc next_inner_delta'
|
201
|
-
puts! outs, 'outs'
|
202
|
-
|
203
|
-
inner = outs[0]
|
204
|
-
outs = outs.select do |out|
|
205
|
-
if 'CALL' == pos.put_call
|
206
|
-
out[:strikePrice] >= inner[:strikePrice].to_f + strategy.next_spread_amount
|
207
|
-
elsif 'PUT' == pos.put_call
|
208
|
-
out[:strikePrice] <= inner[:strikePrice].to_f - strategy.next_spread_amount
|
209
|
-
end
|
210
|
-
end
|
211
|
-
outer = outs[0]
|
212
|
-
|
213
|
-
if inner && outer
|
214
|
-
o_attrs = {
|
215
|
-
expires_on: next_expires_on,
|
216
|
-
put_call: pos.put_call,
|
217
|
-
stock_id: pos.stock_id,
|
218
|
-
}
|
219
|
-
inner_ = Iro::Option.new(o_attrs.merge({
|
220
|
-
strike: inner[:strikePrice],
|
221
|
-
begin_price: ( inner[:bid] + inner[:ask] )/2,
|
222
|
-
begin_delta: inner[:delta],
|
223
|
-
end_price: ( inner[:bid] + inner[:ask] )/2,
|
224
|
-
end_delta: inner[:delta],
|
225
|
-
}))
|
226
|
-
outer_ = Iro::Option.new(o_attrs.merge({
|
227
|
-
strike: outer[:strikePrice],
|
228
|
-
begin_price: ( outer[:bid] + outer[:ask] )/2,
|
229
|
-
begin_delta: outer[:delta],
|
230
|
-
end_price: ( outer[:bid] + outer[:ask] )/2,
|
231
|
-
end_delta: outer[:delta],
|
232
|
-
}))
|
233
|
-
pos.autonxt ||= Iro::Position.new
|
234
|
-
pos.autonxt.update({
|
235
|
-
prev_gain_loss_amount: 'a',
|
236
|
-
status: 'proposed',
|
237
|
-
stock: strategy.stock,
|
238
|
-
inner: inner_,
|
239
|
-
outer: outer_,
|
240
|
-
inner_strike: inner_.strike,
|
241
|
-
outer_strike: outer_.strike,
|
242
|
-
begin_on: Time.now.to_date,
|
243
|
-
expires_on: next_expires_on,
|
244
|
-
purse: purse,
|
245
|
-
strategy: strategy,
|
246
|
-
quantity: 1,
|
247
|
-
autoprev: pos,
|
248
|
-
})
|
249
|
-
|
250
|
-
pos.autonxt.sync
|
251
|
-
pos.autonxt.save!
|
252
|
-
pos.save
|
253
|
-
return pos
|
254
|
-
|
255
|
-
else
|
256
|
-
throw 'zmq - should not happen'
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
## ok
|
263
|
-
def next_expires_on
|
264
|
-
out = expires_on.to_datetime.next_occurring(:monday).next_occurring(:friday)
|
265
|
-
if !out.workday?
|
266
|
-
out = Time.previous_business_day(out)
|
267
|
-
end
|
268
|
-
return out
|
269
|
-
end
|
270
|
-
|
271
|
-
## ok
|
272
|
-
def self.long
|
273
|
-
where( long_or_short: Iro::Strategy::LONG )
|
274
|
-
end
|
275
|
-
|
276
|
-
## ok
|
277
|
-
def self.short
|
278
|
-
where( long_or_short: Iro::Strategy::SHORT )
|
279
|
-
end
|
280
|
-
|
281
|
-
def to_s
|
282
|
-
out = "#{stock} (#{q}) #{expires_on.to_datetime.strftime('%b %d')} #{strategy.long_or_short} ["
|
283
|
-
if Iro::Strategy::LONG == long_or_short
|
284
|
-
if outer.strike
|
285
|
-
out = out + "$#{outer.strike}->"
|
286
|
-
end
|
287
|
-
out = out + "$#{inner.strike}"
|
288
|
-
else
|
289
|
-
out = out + "$#{inner.strike}"
|
290
|
-
if outer.strike
|
291
|
-
out = out + "<-$#{outer.strike}"
|
292
|
-
end
|
293
|
-
end
|
294
|
-
out += "] "
|
295
|
-
return out
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
|
data/app/models/iro/priceitem.rb
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
|
2
|
-
##
|
3
|
-
## Specifically Option or Stock priceitem?
|
4
|
-
## Priceitems are intra-day! See Datapoint for daily data
|
5
|
-
##
|
6
|
-
class Iro::Priceitem
|
7
|
-
include Mongoid::Document
|
8
|
-
include Mongoid::Timestamps
|
9
|
-
store_in collection: 'iro_price_items'
|
10
|
-
|
11
|
-
## PUT, CALL, STOCK
|
12
|
-
field :putCall, type: String ## kind
|
13
|
-
field :symbol, type: String
|
14
|
-
field :description, type: String
|
15
|
-
field :ticker, type: String
|
16
|
-
# belongs_to :stock, inverse_of: :priceitems
|
17
|
-
|
18
|
-
field :bid, type: Float
|
19
|
-
field :bidSize, type: Integer
|
20
|
-
field :ask, type: Float
|
21
|
-
field :askSize, type: Integer
|
22
|
-
field :last, type: Float
|
23
|
-
|
24
|
-
field :openPrice, type: Float
|
25
|
-
field :lowPrice, type: Float
|
26
|
-
field :highPrice, type: Float
|
27
|
-
field :closePrice, type: Float
|
28
|
-
|
29
|
-
field :quote_at, type: DateTime
|
30
|
-
field :quoteTimeInLong, type: Integer
|
31
|
-
field :timestamp, type: Integer
|
32
|
-
field :totalVolume, type: Integer
|
33
|
-
field :mark, type: Float
|
34
|
-
field :exchangeName, type: String
|
35
|
-
field :volatility, type: Float
|
36
|
-
|
37
|
-
field :expirationDate, type: :date
|
38
|
-
field :delta, type: Float
|
39
|
-
field :gamma, type: Float
|
40
|
-
field :theta, type: Float
|
41
|
-
field :openInterest, type: Integer
|
42
|
-
field :strikePrice, type: Float
|
43
|
-
|
44
|
-
def self.my_find props={}
|
45
|
-
lookup = { '$lookup': {
|
46
|
-
'from': 'iro_price_items',
|
47
|
-
'localField': 'date',
|
48
|
-
'foreignField': 'date',
|
49
|
-
'pipeline': [
|
50
|
-
{ '$sort': { 'value': -1 } },
|
51
|
-
],
|
52
|
-
'as': 'dates',
|
53
|
-
} }
|
54
|
-
lookup_merge = { '$replaceRoot': {
|
55
|
-
'newRoot': { '$mergeObjects': [
|
56
|
-
{ '$arrayElemAt': [ "$dates", 0 ] }, "$$ROOT"
|
57
|
-
] }
|
58
|
-
} }
|
59
|
-
|
60
|
-
|
61
|
-
match = { '$match': {
|
62
|
-
'date': {
|
63
|
-
'$gte': props[:begin_on],
|
64
|
-
'$lte': props[:end_on],
|
65
|
-
}
|
66
|
-
} }
|
67
|
-
|
68
|
-
group = { '$group': {
|
69
|
-
'_id': "$date",
|
70
|
-
'my_doc': { '$first': "$$ROOT" }
|
71
|
-
} }
|
72
|
-
|
73
|
-
outs = Iro::Date.collection.aggregate([
|
74
|
-
match,
|
75
|
-
|
76
|
-
lookup,
|
77
|
-
lookup_merge,
|
78
|
-
|
79
|
-
group,
|
80
|
-
{ '$replaceRoot': { 'newRoot': "$my_doc" } },
|
81
|
-
# { '$replaceRoot': { 'newRoot': "$my_doc" } },
|
82
|
-
|
83
|
-
|
84
|
-
{ '$project': { '_id': 0, 'date': 1, 'value': 1 } },
|
85
|
-
{ '$sort': { 'date': 1 } },
|
86
|
-
])
|
87
|
-
|
88
|
-
puts! 'result'
|
89
|
-
pp outs.to_a
|
90
|
-
# puts! outs.to_a, 'result'
|
91
|
-
end
|
92
|
-
|
93
|
-
end
|
data/app/models/iro/purse.rb
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'distribution'
|
3
|
-
N = Distribution::Normal
|
4
|
-
|
5
|
-
class Iro::Purse
|
6
|
-
include Mongoid::Document
|
7
|
-
include Mongoid::Timestamps
|
8
|
-
include Mongoid::Paranoia
|
9
|
-
store_in collection: 'iro_purses'
|
10
|
-
|
11
|
-
field :slug
|
12
|
-
validates :slug, presence: true, uniqueness: true
|
13
|
-
index({ slug: -1 }, { unique: true })
|
14
|
-
|
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
|
18
|
-
|
19
|
-
belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :strategies
|
20
|
-
|
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
|
25
|
-
|
26
|
-
## for rolling only:
|
27
|
-
field :height, type: :integer, default: 100
|
28
|
-
|
29
|
-
field :mark_every_n_usd, type: :float, default: 1
|
30
|
-
field :n_next_positions, type: :integer, default: 5
|
31
|
-
|
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
|
65
|
-
|
66
|
-
def to_s
|
67
|
-
slug
|
68
|
-
end
|
69
|
-
def self.list
|
70
|
-
[[nil,nil]] + all.map { |p| [p, p.id] }
|
71
|
-
end
|
72
|
-
end
|
data/app/models/iro/stock.rb
DELETED
@@ -1,134 +0,0 @@
|
|
1
|
-
include Math
|
2
|
-
require 'business_time'
|
3
|
-
|
4
|
-
##
|
5
|
-
## https://www.macrotrends.net/stocks/charts/META/meta-platforms/stock-price-history
|
6
|
-
##
|
7
|
-
class Iro::Stock
|
8
|
-
include Mongoid::Document
|
9
|
-
include Mongoid::Timestamps
|
10
|
-
include Mongoid::Paranoia
|
11
|
-
store_in collection: 'iro_stocks'
|
12
|
-
|
13
|
-
STATUS_ACTIVE = 'active'
|
14
|
-
STATUS_INACTIVE = 'inactive'
|
15
|
-
STATUSES = [ nil, 'active', 'inactive' ]
|
16
|
-
def self.active
|
17
|
-
where( status: STATUS_ACTIVE )
|
18
|
-
end
|
19
|
-
field :status, default: STATUS_ACTIVE
|
20
|
-
|
21
|
-
field :ticker
|
22
|
-
validates :ticker, uniqueness: true, presence: true
|
23
|
-
index({ ticker: -1 }, { unique: true })
|
24
|
-
def symbol; ticker; end
|
25
|
-
def symbol= a; ticker = a; end
|
26
|
-
|
27
|
-
field :last, type: :float
|
28
|
-
field :options_price_increment, type: :float
|
29
|
-
|
30
|
-
field :stdev, type: :float
|
31
|
-
|
32
|
-
has_many :positions, class_name: 'Iro::Position', inverse_of: :stock
|
33
|
-
has_many :strategies, class_name: 'Iro::Strategy', inverse_of: :stock
|
34
|
-
has_many :purses, class_name: 'Iro::Purse', inverse_of: :stock
|
35
|
-
has_many :options, class_name: 'Iro::Option', inverse_of: :stock
|
36
|
-
has_many :priceitems, inverse_of: :stock
|
37
|
-
|
38
|
-
default_scope { order_by({ ticker: :asc }) }
|
39
|
-
|
40
|
-
## my_find
|
41
|
-
def self.f ticker
|
42
|
-
self.find_by ticker: ticker
|
43
|
-
end
|
44
|
-
|
45
|
-
def to_s
|
46
|
-
ticker
|
47
|
-
end
|
48
|
-
def self.list
|
49
|
-
[[nil,nil]] + all.map { |sss| [ sss.ticker, sss.id ] }
|
50
|
-
end
|
51
|
-
def self.tickers_list
|
52
|
-
[[nil,nil]] + all.map { |sss| [ sss.ticker, sss.ticker ] }
|
53
|
-
end
|
54
|
-
|
55
|
-
=begin
|
56
|
-
stock = Iro::Stock.find_by( ticker: 'NVDA' )
|
57
|
-
|
58
|
-
duration = 1.month
|
59
|
-
stock.volatility_from_mo
|
60
|
-
|
61
|
-
duration = 1.year
|
62
|
-
stock.volatility_from_yr
|
63
|
-
|
64
|
-
=end
|
65
|
-
field :volatility, type: :float
|
66
|
-
def volatility duration: 1.year, recompute: false
|
67
|
-
if self[:volatility]
|
68
|
-
if !recompute
|
69
|
-
return self[:volatility]
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
stock = self
|
74
|
-
begin_on = Time.now - duration - 1.day
|
75
|
-
points = Iro::Datapoint.where( kind: 'STOCK', symbol: stock.ticker,
|
76
|
-
:date.gte => begin_on,
|
77
|
-
).order_by( date: :asc )
|
78
|
-
|
79
|
-
puts! [points.first.date, points.last.date], "from,to"
|
80
|
-
|
81
|
-
points_p = []
|
82
|
-
points.each_with_index do |p, idx|
|
83
|
-
next if idx == 0
|
84
|
-
prev = points[idx-1]
|
85
|
-
|
86
|
-
out = p.value / prev.value - 1
|
87
|
-
points_p.push out
|
88
|
-
end
|
89
|
-
n = points_p.length
|
90
|
-
|
91
|
-
avg = points_p.reduce(&:+) / n
|
92
|
-
_sum_of_sq = []
|
93
|
-
points_p.map do |p|
|
94
|
-
_sum_of_sq.push( ( p - avg )*( p - avg ) )
|
95
|
-
end
|
96
|
-
sum_of_sq = _sum_of_sq.reduce( &:+ ) / n
|
97
|
-
|
98
|
-
# n_periods = begin_on.to_date.business_days_until( Date.today )
|
99
|
-
out = Math.sqrt( sum_of_sq )*sqrt( n )
|
100
|
-
adjustment = 2.0
|
101
|
-
out = out * adjustment
|
102
|
-
puts! out, 'volatility (adjusted)'
|
103
|
-
self.update volatility: out
|
104
|
-
return out
|
105
|
-
end
|
106
|
-
|
107
|
-
def volatility_from_mo
|
108
|
-
volatility( duration: 1.month )
|
109
|
-
end
|
110
|
-
def volatility_from_yr
|
111
|
-
volatility( duration: 1.year )
|
112
|
-
end
|
113
|
-
def stdev recompute: nil
|
114
|
-
if !self[:stdev] || recompute
|
115
|
-
out = volatility_from_yr
|
116
|
-
self[:stdev] = out
|
117
|
-
save( validate: false )
|
118
|
-
return out
|
119
|
-
else
|
120
|
-
self[:stdev]
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
## stdev
|
125
|
-
## From: https://stackoverflow.com/questions/19484891/how-do-i-find-the-standard-deviation-in-ruby
|
126
|
-
# contents = [1,2,3,4,5,6,7,8,9]
|
127
|
-
# n = contents.size # => 9
|
128
|
-
# contents.map!(&:to_f) # => [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
|
129
|
-
# mean = contents.reduce(&:+)/n # => 5.0
|
130
|
-
# sum_sqr = contents.map {|x| x * x}.reduce(&:+) # => 285.0
|
131
|
-
# std_dev = Math.sqrt((sum_sqr - n * mean * mean)/(n-1)) # => 2.7386127875258306
|
132
|
-
|
133
|
-
|
134
|
-
end
|