iron_warbler 2.0.7.43 → 2.0.7.45

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/iron_warbler/utils.scss +9 -9
  3. data/app/controllers/iro/positions_controller.rb +1 -0
  4. data/app/controllers/iro/purses_controller.rb +3 -1
  5. data/app/controllers/iro/strategies_controller.rb +8 -3
  6. data/app/views/iro/positions/_form.haml +1 -1
  7. data/app/views/iro/positions/{_gameui_long_debit_call_spread.haml-trash → _gameui_spread.haml} +9 -8
  8. data/app/views/iro/positions/_header_spread.haml +12 -0
  9. data/app/views/iro/positions/_new.haml +4 -0
  10. data/app/views/iro/positions/done/_gameui_short_debit_put_spread.haml +1 -0
  11. data/app/views/iro/positions/done/_header_short_debit_put_spread.haml +1 -0
  12. data/app/views/iro/purses/_form.haml +3 -3
  13. data/app/views/iro/purses/index.haml +3 -2
  14. data/app/views/iro/strategies/_form_spread.haml +69 -0
  15. data/app/views/iro/strategies/{_form.haml → _form_wheel.haml} +12 -12
  16. data/app/views/iro/strategies/_header.haml +2 -1
  17. data/app/views/iro/strategies/_table.haml +3 -5
  18. data/app/views/iro/strategies/edit.haml +1 -1
  19. data/app/views/iro/strategies/index.haml +2 -1
  20. data/app/views/iro/strategies/new.haml +1 -1
  21. data/app/views/layouts/iro/application.haml +1 -1
  22. data/config/routes.rb +2 -0
  23. data/lib/iron_warbler.rb +2 -1
  24. data/lib/tasks/iro_tasks.rake +6 -0
  25. metadata +20 -30
  26. data/app/models/iro/alert.rb +0 -63
  27. data/app/models/iro/datapoint.rb +0 -187
  28. data/app/models/iro/date.rb +0 -10
  29. data/app/models/iro/option.rb +0 -151
  30. data/app/models/iro/option_black_scholes.rb +0 -149
  31. data/app/models/iro/position.rb +0 -299
  32. data/app/models/iro/priceitem.rb +0 -93
  33. data/app/models/iro/purse.rb +0 -72
  34. data/app/models/iro/stock.rb +0 -134
  35. data/app/models/iro/strategy.rb +0 -264
  36. data/app/views/iro/positions/_gameui_short_debit_put_spread.haml +0 -1
  37. data/app/views/iro/positions/_gameui_short_debit_put_spread.haml-trash +0 -40
  38. data/app/views/iro/positions/_header_short_debit_put_spread.haml +0 -1
  39. data/app/views/iro/positions/roll.haml-trash +0 -42
  40. /data/app/views/iro/positions/{_gameui_covered_call.haml-bk → done/_gameui_covered_call.haml-bk} +0 -0
  41. /data/app/views/iro/positions/{_gameui_long_credit_put_spread.haml → done/_gameui_long_credit_put_spread.haml} +0 -0
  42. /data/app/views/iro/positions/{_gameui_long_debit_call_spread.haml → done/_gameui_long_debit_call_spread.haml} +0 -0
  43. /data/app/views/iro/positions/{_gameui_short_credit_call_spread.haml → done/_gameui_short_credit_call_spread.haml} +0 -0
  44. /data/app/views/iro/positions/{_header_long_credit_put_spread.haml → done/_header_long_credit_put_spread.haml} +0 -0
  45. /data/app/views/iro/positions/{_header_long_debit_call_spread.haml → done/_header_long_debit_call_spread.haml} +0 -0
  46. /data/app/views/iro/positions/{_header_short_credit_call_spread.haml → done/_header_short_credit_call_spread.haml} +0 -0
  47. /data/app/views/iro/positions/{roll-cc.haml-bk → done/roll-cc.haml-bk} +0 -0
  48. /data/app/views/iro/purses/{gameui.haml-bk → done/gameui.haml-bk} +0 -0
  49. /data/app/views/iro/purses/{gameui.haml-bk2 → done/gameui.haml-bk2} +0 -0
  50. /data/app/views/iro/stocks/{_grid_is_long.haml → _grid_long.haml} +0 -0
  51. /data/app/views/iro/stocks/{_grid_is_short.haml → _grid_short.haml} +0 -0
@@ -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
-
@@ -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
@@ -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
@@ -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