iron_warbler 2.0.7.8 → 2.0.7.10

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/iron_warbler/positions.scss +47 -0
  3. data/app/assets/stylesheets/iron_warbler/strategies.scss +0 -0
  4. data/app/assets/stylesheets/iron_warbler/utils.css +44 -0
  5. data/app/controllers/iro/alerts_controller.rb +6 -6
  6. data/app/controllers/iro/datapoints_controller.rb +0 -2
  7. data/app/controllers/iro/positions_controller.rb +62 -0
  8. data/app/controllers/iro/profiles_controller.rb +0 -2
  9. data/app/controllers/iro/purses_controller.rb +65 -0
  10. data/app/controllers/iro/stocks_controller.rb +10 -4
  11. data/app/controllers/iro/strategies_controller.rb +66 -0
  12. data/app/models/iro/option.rb +0 -7
  13. data/app/models/iro/position.rb +222 -0
  14. data/app/models/iro/purse.rb +17 -0
  15. data/app/models/iro/stock.rb +12 -2
  16. data/app/models/iro/strategy.rb +38 -0
  17. data/app/models/tda/option.rb +137 -0
  18. data/app/models/tda/{api.rb → stock.rb} +1 -1
  19. data/app/views/iro/_main_header.haml +16 -6
  20. data/app/views/iro/alerts/index.haml +1 -1
  21. data/app/views/iro/positions/_form.haml +59 -0
  22. data/app/views/iro/positions/_reasons.haml +4 -0
  23. data/app/views/iro/positions/_table.haml +137 -0
  24. data/app/views/iro/positions/edit.haml +4 -0
  25. data/app/views/iro/positions/new.haml +4 -0
  26. data/app/views/iro/purses/_form.haml +9 -0
  27. data/app/views/iro/purses/edit.haml +3 -0
  28. data/app/views/iro/purses/index.haml +11 -0
  29. data/app/views/iro/purses/show.haml +10 -0
  30. data/app/views/iro/stocks/_form.haml +4 -0
  31. data/app/views/iro/strategies/_form.haml +37 -0
  32. data/app/views/iro/strategies/_header.haml +8 -0
  33. data/app/views/iro/strategies/_show.haml +18 -0
  34. data/app/views/iro/strategies/_table.haml +18 -0
  35. data/app/views/iro/strategies/edit.haml +3 -0
  36. data/app/views/iro/strategies/new.haml +3 -0
  37. data/config/routes.rb +6 -0
  38. data/lib/iron_warbler.rb +4 -0
  39. data/lib/tasks/iro_tasks.rake +35 -0
  40. metadata +42 -13
  41. data/app/assets/stylesheets/iron_warbler/main.css +0 -13
  42. data/app/assets/stylesheets/scaffold.css +0 -80
  43. data/app/views/iro/alerts/edit.html.erb +0 -6
  44. data/app/views/iro/alerts/new.html.erb +0 -5
  45. data/app/views/iro/alerts/show.html.erb +0 -34
  46. data/app/views/iro/profiles/_form.html.erb +0 -32
  47. data/app/views/iro/profiles/edit.html.erb +0 -6
  48. data/app/views/iro/profiles/index.html.erb +0 -31
  49. data/app/views/iro/profiles/new.html.erb +0 -5
  50. data/app/views/iro/profiles/show.html.erb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ee2560d39aa4a4a279294e7611cc5e5564712c59931e0ae5f1d7ea91140aba5
4
- data.tar.gz: cf46d95a353f1097a78aa1009a9ffe17d6b305810def2cb440782fa46e59ac8a
3
+ metadata.gz: d7b7685e4696ff34f93ea5bd1a5f3931e1aa0718cb893de9ccb589234fd539e4
4
+ data.tar.gz: c11b8fb78c052fee8584ce20e3c9673d74778945b4ba5d469e30f10e7521d7b7
5
5
  SHA512:
6
- metadata.gz: 6ebc5bf69e74d48abd1cdcc2c097a5c59aea38c971bd0298850920e217576a90ea0d3520d423648af9df20591ccfa4f9cc637a280863b49ba48acd1cdd9aa78a
7
- data.tar.gz: 84c43a18c988669e34f19ecd961cebfe971795e1cc3ca628405d8a1c487b7805c8e443a38dd4a1b05f1c37c2cab304e8e412c98604cb6ff0e27d296deaa9c539
6
+ metadata.gz: a54e555e30a9197f6414c7989b652699a7d5bd087294889a6cc1fd5cf942818c8fb0ca3ab1eb50fa15f83be11f5e310caef40187c7e9097fe77721d3eb3e0fd0
7
+ data.tar.gz: 1bd3bcef86e4980e6f45c96d3096a9bcbe7975425bac15b16129acaf2f5f4ccf0ccb1c3fab60e6e71b67bf4ab589c4999eb09871cd7190680c25fed1410a32c2
@@ -0,0 +1,47 @@
1
+
2
+ .positions--table {
3
+
4
+ table {
5
+ td {
6
+ text-align: center;
7
+ }
8
+ td.actions,
9
+ td.next_position,
10
+ td.strategy,
11
+ ._ {
12
+ text-align: left;
13
+ }
14
+ th {
15
+ border: 1px solid red;
16
+
17
+ > * {
18
+ border: 1px solid yellow;
19
+ // background: #ddd;
20
+
21
+ transform-origin: 0 0;
22
+ rotate: -40deg;
23
+
24
+ padding: .4em 0;
25
+ width: 120px;
26
+
27
+ }
28
+
29
+ }
30
+
31
+ th.begin_price {
32
+ > div {
33
+ background: cyan;
34
+ }
35
+ }
36
+
37
+ th.end_delta {
38
+ width: 50px;
39
+ }
40
+ th.next_position {
41
+ width: 160px;
42
+ }
43
+ th.next_symbol {
44
+ width: 120px;
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,44 @@
1
+
2
+ /* F */
3
+
4
+ .flex-row {
5
+ display: flex;
6
+ margin-bottom: 0.4em;
7
+ }
8
+ .field {
9
+ min-width: 100px;
10
+ margin-right: 1em;
11
+ }
12
+
13
+ /* M */
14
+
15
+ .modal-absolute {
16
+ border: 1px solid green;
17
+ border-radius: 5px;
18
+ box-shadow: 2px 2px;
19
+
20
+ padding: 0.5em;
21
+
22
+ position: absolute;
23
+
24
+ min-width: 200px;
25
+ width: 400px;
26
+
27
+ min-height: 200px;
28
+ height: 300px;
29
+ /* overflow: auto; */
30
+
31
+ background: white;
32
+
33
+ z-index: 2;
34
+
35
+ }
36
+
37
+
38
+
39
+ /* W */
40
+
41
+ .w-min-50px {
42
+ min-width: 50px;
43
+ }
44
+
@@ -4,7 +4,8 @@ class Iro::AlertsController < Iro::ApplicationController
4
4
  before_action :set_lists
5
5
 
6
6
  def create
7
- @alert = Iro::Alert.new(alert_params)
7
+ @alert = Iro::Alert.new params[:alert].permit!
8
+ authorize! :create, @alert
8
9
  if @alert.save
9
10
  redirect_to action: :index, notice: 'Alert was successfully created.'
10
11
  else
@@ -14,17 +15,20 @@ class Iro::AlertsController < Iro::ApplicationController
14
15
 
15
16
  def destroy
16
17
  @alert = Iro::Alert.find(params[:id])
18
+ authorize! :destroy, @alert
17
19
  @alert.destroy
18
20
  redirect_to action: :index, notice: 'Alert was successfully destroyed.'
19
21
  end
20
22
 
21
23
  def index
22
24
  @alerts = Iro::Alert.all
25
+ authorize! :index, Iro::Alert
23
26
  end
24
27
 
25
28
  def update
26
29
  @alert = Iro::Alert.find(params[:id])
27
- if @alert.update(alert_params)
30
+ authorize! :update, @alert
31
+ if @alert.update params[:alert].permit!
28
32
  redirect_to action: :index, notice: 'Alert was successfully updated.'
29
33
  else
30
34
  render :edit
@@ -36,10 +40,6 @@ class Iro::AlertsController < Iro::ApplicationController
36
40
  ##
37
41
  private
38
42
 
39
- def alert_params
40
- params.require(:alert).permit(:class_name, :kind, :symbol, :direction, :strike, :profile_id)
41
- end
42
-
43
43
  def set_lists
44
44
  # @profiles_list = Wco::Profile.list
45
45
  @stocks_list = [[nil,nil]] + Iro::Stock.active.map { |s| [ s.ticker, s.ticker ] }
@@ -1,6 +1,4 @@
1
1
 
2
- # require_dependency "iro/application_controller"
3
-
4
2
  class Iro::DatapointsController < Iro::ApplicationController
5
3
 
6
4
  ## params: d, k, v
@@ -0,0 +1,62 @@
1
+
2
+ class Iro::PositionsController < Iro::ApplicationController
3
+
4
+ before_action :set_lists
5
+
6
+ def new
7
+ @position = Iro::Position.new purse_id: params[:purse_id]
8
+ authorize! :new, @posision
9
+ end
10
+
11
+ def create
12
+ @position = Iro::Position.new params[:position].permit!
13
+ authorize! :create, @position
14
+
15
+ if @position.save
16
+ flash_notice @position
17
+ redirect_to controller: :purses, action: :show, id: @position.purse_id.to_s
18
+ else
19
+ flash_alert @position
20
+ redirect_to request.referrer
21
+ end
22
+ end
23
+
24
+ def destroy
25
+ @position = Iro::Position.find params[:id]
26
+ authorize! :destroy, @position
27
+ @position.delete
28
+ flash_notice "Probably ok"
29
+ redirect_to request.referrer
30
+ end
31
+
32
+ def edit
33
+ @position = Iro::Position.find params[:id]
34
+ authorize! :edit, @position
35
+
36
+ @strategies_list = Iro::Strategy.for_ticker( @position.ticker ).list
37
+ end
38
+
39
+ def update
40
+ @position = Iro::Position.find params[:id]
41
+ authorize! :update, @position
42
+
43
+ if @position.update params[:position].permit!
44
+ flash_notice @position
45
+ redirect_to controller: :purses, action: :show, id: @position.purse_id.to_s
46
+ else
47
+ flash_alert @position
48
+ redirect_to request.referrer
49
+ end
50
+ end
51
+
52
+ ##
53
+ ## private
54
+ ##
55
+ private
56
+
57
+ def set_lists
58
+ @strategies_list = Iro::Strategy.list
59
+ @tickers_list = Iro::Stock.tickers_list
60
+ end
61
+
62
+ end
@@ -1,6 +1,4 @@
1
1
 
2
- # require_dependency "iro/application_controller"
3
-
4
2
  class Iro::ProfilesController < Iro::ApplicationController
5
3
  before_action :set_profile, only: [:show, :edit, :update, :destroy]
6
4
 
@@ -0,0 +1,65 @@
1
+
2
+ class Iro::PursesController < Iro::ApplicationController
3
+
4
+ before_action :set_lists
5
+
6
+ def create
7
+ @purse = Iro::Purse.new params[:purse].permit!
8
+ authorize! :create, @purse
9
+ if @purse.save
10
+ redirect_to action: :index, notice: 'Purse was successfully created.'
11
+ else
12
+ render :new
13
+ end
14
+ end
15
+
16
+ def destroy
17
+ @purse = Iro::Purse.find(params[:id])
18
+ authorize! :destroy, @purse
19
+ @purse.destroy
20
+ redirect_to action: :index, notice: 'Purse was successfully destroyed.'
21
+ end
22
+
23
+ def edit
24
+ @purse = Iro::Purse.find(params[:id])
25
+ authorize! :edit, @purse
26
+
27
+
28
+ end
29
+
30
+ def index
31
+ @purses = Iro::Purse.all
32
+ authorize! :index, Iro::Purse
33
+ end
34
+
35
+ def show
36
+ @purse = Iro::Purse.find(params[:id])
37
+ authorize! :show, @purse
38
+
39
+ @positions = Iro::Position.all
40
+ end
41
+
42
+ def update
43
+ @purse = Iro::Purse.find(params[:id])
44
+ authorize! :update, @purse
45
+ if @purse.update params[:purse].permit!
46
+ redirect_to action: :index, notice: 'Purse was successfully updated.'
47
+ else
48
+ render :edit
49
+ end
50
+ end
51
+
52
+ ##
53
+ ## private
54
+ ##
55
+ private
56
+
57
+ def set_lists
58
+ # @profiles_list = Wco::Profile.list
59
+ @stocks_list = [[nil,nil]] + Iro::Stock.active.map { |s| [ s.ticker, s.ticker ] }
60
+
61
+ end
62
+
63
+
64
+ end
65
+
@@ -12,6 +12,7 @@ class Iro::StocksController < Iro::ApplicationController
12
12
 
13
13
  def new
14
14
  @stock = Iro::Stock.new
15
+ authorize! :new, @stock
15
16
  end
16
17
 
17
18
  def edit
@@ -19,20 +20,25 @@ class Iro::StocksController < Iro::ApplicationController
19
20
 
20
21
  def create
21
22
  @stock = Iro::Stock.new(stock_params)
23
+ authorize! :create, @stock
22
24
 
23
25
  if @stock.save
24
- redirect_to action: :index, notice: 'Stock was successfully created.'
26
+ flash_notice @stock
25
27
  else
26
- render :new
28
+ flash_alert @stock
27
29
  end
30
+ redirect_to action: :index
28
31
  end
29
32
 
30
33
  def update
34
+ @stock = Iro::Stock.find params[:id]
35
+ authorize! :update, @stock
31
36
  if @stock.update(stock_params)
32
- redirect_to @stock, notice: 'Stock was successfully updated.'
37
+ flash_notice @stock
33
38
  else
34
- render :edit
39
+ flash_alert @stock
35
40
  end
41
+ redirect_to request.referrer
36
42
  end
37
43
 
38
44
  def destroy
@@ -0,0 +1,66 @@
1
+
2
+ class Iro::StrategiesController < Iro::ApplicationController
3
+
4
+ before_action :set_lists
5
+
6
+ def new
7
+ @strategy = Iro::Strategy.new
8
+ authorize! :new, @posision
9
+ end
10
+
11
+ def create
12
+ @strategy = Iro::Strategy.new params[:strategy].permit!
13
+ authorize! :create, @strategy
14
+
15
+ if @strategy.save
16
+ flash_notice @strategy
17
+ else
18
+ flash_alert @strategy
19
+ end
20
+
21
+ redirect_to action: :index
22
+ end
23
+
24
+ def destroy
25
+ @strategy = Iro::Strategy.find params[:id]
26
+ authorize! :destroy, @strategy
27
+ @strategy.delete
28
+ flash_notice "Probably ok"
29
+ redirect_to request.referrer
30
+ end
31
+
32
+ def edit
33
+ @strategy = Iro::Strategy.find params[:id]
34
+ authorize! :edit, @strategy
35
+ end
36
+
37
+ def index
38
+ authorize! :index, Iro::Strategy
39
+ @strategies = Iro::Strategy.all
40
+ render '_table'
41
+ end
42
+
43
+ def update
44
+ @strategy = Iro::Strategy.find params[:id]
45
+ authorize! :update, @strategy
46
+
47
+ if @strategy.update params[:strategy].permit!
48
+ flash_notice @strategy
49
+ else
50
+ flash_alert @strategy
51
+ end
52
+
53
+ redirect_to action: :index
54
+ end
55
+
56
+ ##
57
+ ## private
58
+ ##
59
+ private
60
+
61
+ def set_lists
62
+ @strategies_list = Iro::Strategy.list
63
+ @tickers_list = Iro::Stock.tickers_list
64
+ end
65
+
66
+ end
@@ -5,13 +5,6 @@ class Iro::Option
5
5
  include Mongoid::Timestamps
6
6
  store_in collection: 'iro_options'
7
7
 
8
- # STATUS_ACTIVE = 'active'
9
- # STATUS_INACTIVE = 'inactive'
10
- # STATUSES = [ 'active', 'inactive' ]
11
- # def self.active
12
- # where( status: STATUS_ACTIVE )
13
- # end
14
-
15
8
  # field :ticker
16
9
  # validates :ticker, uniqueness: true, presence: true
17
10
 
@@ -0,0 +1,222 @@
1
+
2
+ class Iro::Position
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ store_in collection: 'iro_positions'
6
+
7
+ STATUS_ACTIVE = 'active'
8
+ STATUS_PROPOSED = 'proposed'
9
+ STATUSES = [ nil, 'active', 'inactive', 'proposed' ]
10
+ field :status
11
+ validates :status, presence: true
12
+ scope :active, ->{ where( status: 'active' ) }
13
+
14
+ belongs_to :purse, class_name: 'Iro::Purse', inverse_of: :positions
15
+ belongs_to :strategy, class_name: 'Iro::Strategy', inverse_of: :positions
16
+
17
+ field :ticker
18
+ validates :ticker, presence: true
19
+ index({ purse_id: 1, ticker: 1 })
20
+
21
+ KINDS = [ nil, 'covered_call', 'credit_put_spread', 'credit_call_spread' ]
22
+ field :kind
23
+
24
+ field :strike, type: :float
25
+ validates :strike, presence: true
26
+
27
+ field :expires_on
28
+ validates :expires_on, presence: true
29
+
30
+ field :quantity, type: :integer
31
+ validates :quantity, presence: true
32
+
33
+ field :begin_on
34
+ field :begin_price, type: :float
35
+ field :begin_delta, type: :float
36
+
37
+ field :end_on
38
+ field :end_price, type: :float
39
+ field :end_delta, type: :float
40
+
41
+ field :net_amount
42
+ field :net_percent
43
+
44
+ def current_underlying_strike
45
+ Iro::Stock.find_by( ticker: ticker ).last
46
+ end
47
+
48
+ def refresh
49
+ out = Tda::Option.get_quote({
50
+ contractType: 'CALL',
51
+ strike: strike,
52
+ expirationDate: expires_on,
53
+ ticker: ticker,
54
+ })
55
+ update({
56
+ end_delta: out[:delta],
57
+ end_price: out[:last],
58
+ })
59
+ print '_'
60
+ end
61
+
62
+
63
+ field :next_delta, type: :float
64
+ field :next_outcome, type: :float
65
+ field :next_symbol
66
+ field :next_mark
67
+ field :next_reasons, type: :array, default: []
68
+ field :should_rollp, type: :float
69
+
70
+ def should_roll?
71
+ puts! 'shold_roll?'
72
+
73
+ update({
74
+ next_reasons: [],
75
+ next_symbol: nil,
76
+ next_delta: nil,
77
+ })
78
+
79
+ if must_roll?
80
+ out = 1.0
81
+ elsif can_roll?
82
+
83
+ if end_delta < strategy.threshold_delta
84
+ next_reasons.push "delta is lower than threshold"
85
+ out = 0.91
86
+ elsif 1 - end_price/begin_price > strategy.threshold_netp
87
+ next_reasons.push "made enough percent profit (dubious)"
88
+ out = 0.61
89
+ else
90
+ next_reasons.push "neutral"
91
+ out = 0.33
92
+ end
93
+
94
+ else
95
+ out = 0.0
96
+ end
97
+
98
+ update({
99
+ next_delta: next_position[:delta],
100
+ next_outcome: next_position[:mark] - end_price,
101
+ next_symbol: next_position[:symbol],
102
+ next_mark: next_position[:mark],
103
+ should_rollp: out,
104
+ # status: Iro::Position::STATE_PROPOSED,
105
+ })
106
+
107
+ puts! next_reasons, 'next_reasons'
108
+ puts! out, 'out'
109
+ return out > 0.5
110
+ end
111
+
112
+
113
+ ## expires_on = cc.expires_on ; nil
114
+ def can_roll?
115
+ ## only if less than 7 days left
116
+ ( expires_on.to_date - Time.now.to_date ).to_i < 7
117
+ end
118
+
119
+ ## If I'm near below water
120
+ ##
121
+ ## expires_on = cc.expires_on ; strategy = cc.strategy ; strike = cc.strike ; nil
122
+ def must_roll?
123
+ if ( current_underlying_strike + strategy.buffer_above_water ) > strike
124
+ return true
125
+ end
126
+ ## @TODO: This one should not happen, I should log appropriately. _vp_ 2023-03-19
127
+ if ( expires_on.to_date - Time.now.to_date ).to_i < 1
128
+ return true
129
+ end
130
+ end
131
+
132
+ ## strike = cc.strike ; strategy = cc.strategy ; nil
133
+ def near_below_water?
134
+ strike < current_underlying_strike + strategy.buffer_above_water
135
+ end
136
+
137
+
138
+
139
+ ## 2023-03-18 _vp_ Continue.
140
+ ## 2023-03-19 _vp_ Continue.
141
+ ## 2023-08-05 _vp_ an Important method
142
+ ##
143
+ ## expires_on = cc.expires_on ; strategy = cc.strategy ; ticker = cc.ticker ; end_price = cc.end_price ; next_expires_on = cc.next_expires_on ; nil
144
+ ##
145
+ ## out.map { |p| [ p[:strikePrice], p[:delta] ] }
146
+ ##
147
+ def next_position
148
+ return @next_position if @next_position
149
+ return {} if ![ STATUS_ACTIVE, STATUS_PROPOSED ].include?( status )
150
+
151
+ ## 7 days ahead - not configurable so far
152
+ out = Tda::Option.get_quotes({
153
+ ticker: ticker,
154
+ expirationDate: next_expires_on,
155
+ contractType: 'CALL',
156
+ })
157
+
158
+ ## above_water
159
+ if strategy.buffer_above_water.present?
160
+ out = out.select do |i|
161
+ i[:strikePrice] > current_underlying_strike + strategy.buffer_above_water
162
+ end
163
+ # next_reasons.push "buffer_above_water above #{current_underlying_strike + strategy.buffer_above_water}"
164
+ end
165
+
166
+ if near_below_water?
167
+ msg = "Panic! climb at a loss. Skip the rest of the calculation."
168
+ next_reasons.push msg
169
+ ## @TODO: if not enough money in the purse, cannot roll? 2023-03-19
170
+
171
+ # byebug
172
+
173
+ ## Take a small loss here.
174
+ prev = nil
175
+ out.each_with_index do |i, idx|
176
+ next if idx == 0
177
+ if i[:last] < end_price
178
+ prev ||= i
179
+ end
180
+ end
181
+ out = [ prev ]
182
+
183
+ else
184
+ ## Normal flow, making money.
185
+ ## @TODO: test! _vp_ 2023-03-19
186
+
187
+ ## next_min_strike
188
+ if strategy.next_min_strike.present?
189
+ out = out.select do |i|
190
+ i[:strikePrice] >= strategy.next_min_strike
191
+ end
192
+ # next_reasons.push "next_min_strike above #{strategy.next_min_strike}"
193
+ end
194
+ # json_puts! out.map { |p| [p[:delta], p[:symbol]] }, 'next_min_strike'
195
+
196
+ ## max_delta
197
+ if strategy.next_max_delta.present?
198
+ out = out.select do |i|
199
+ i[:delta] = 0.0 if i[:delta] == "NaN"
200
+ i[:delta] <= strategy.next_max_delta
201
+ end
202
+ # next_reasons.push "next_max_delta below #{strategy.next_max_delta}"
203
+ end
204
+ # json_puts! out.map { |p| [p[:delta], p[:symbol]] }, 'next_max_delta'
205
+ end
206
+
207
+ @next_position = out[0] || {}
208
+ end
209
+
210
+ ## @TODO: Test this. _vp_ 2023-04-01
211
+ def next_expires_on
212
+ out = expires_on.to_time + 7.days
213
+ while !out.friday?
214
+ out = out + 1.day
215
+ end
216
+ while !out.workday?
217
+ out = out - 1.day
218
+ end
219
+ return out
220
+ end
221
+
222
+ end
@@ -0,0 +1,17 @@
1
+
2
+ class Iro::Purse
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ store_in collection: 'iro_purses'
6
+
7
+ field :slug
8
+ validates :slug, presence: true, uniqueness: true
9
+ index({ slug: -1 }, { unique: true })
10
+
11
+ has_many :positions, class_name: 'Iro::Position', inverse_of: :purse
12
+
13
+ def to_s
14
+ slug
15
+ end
16
+
17
+ end
@@ -1,5 +1,4 @@
1
1
 
2
-
3
2
  class Iro::Stock
4
3
  include Mongoid::Document
5
4
  include Mongoid::Timestamps
@@ -7,13 +6,24 @@ class Iro::Stock
7
6
 
8
7
  STATUS_ACTIVE = 'active'
9
8
  STATUS_INACTIVE = 'inactive'
10
- STATUSES = [ 'active', 'inactive' ]
9
+ STATUSES = [ nil, 'active', 'inactive' ]
11
10
  def self.active
12
11
  where( status: STATUS_ACTIVE )
13
12
  end
13
+ field :status
14
14
 
15
15
  field :ticker
16
16
  validates :ticker, uniqueness: true, presence: true
17
17
 
18
+ field :last, type: :float
19
+
20
+ def self.list
21
+ end
22
+
23
+ def self.tickers_list
24
+ [nil] + all.map( &:ticker )
25
+ end
26
+
27
+ # has_many :strategies, class_name: 'Iro::Strategy', inverse_of: :stock
18
28
 
19
29
  end