iron_warbler 2.0.7.8 → 2.0.7.9

Sign up to get free protection for your applications and to get access to all the features.
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/views/iro/_main_header.haml +16 -6
  19. data/app/views/iro/alerts/index.haml +1 -1
  20. data/app/views/iro/positions/_form.haml +59 -0
  21. data/app/views/iro/positions/_reasons.haml +4 -0
  22. data/app/views/iro/positions/_table.haml +137 -0
  23. data/app/views/iro/positions/edit.haml +4 -0
  24. data/app/views/iro/positions/new.haml +4 -0
  25. data/app/views/iro/purses/_form.haml +9 -0
  26. data/app/views/iro/purses/edit.haml +3 -0
  27. data/app/views/iro/purses/index.haml +11 -0
  28. data/app/views/iro/purses/show.haml +10 -0
  29. data/app/views/iro/stocks/_form.haml +4 -0
  30. data/app/views/iro/strategies/_form.haml +37 -0
  31. data/app/views/iro/strategies/_header.haml +8 -0
  32. data/app/views/iro/strategies/_show.haml +18 -0
  33. data/app/views/iro/strategies/_table.haml +18 -0
  34. data/app/views/iro/strategies/edit.haml +3 -0
  35. data/app/views/iro/strategies/new.haml +3 -0
  36. data/config/routes.rb +6 -0
  37. data/lib/iron_warbler.rb +4 -0
  38. data/lib/tasks/iro_tasks.rake +35 -0
  39. metadata +42 -13
  40. data/app/assets/stylesheets/iron_warbler/main.css +0 -13
  41. data/app/assets/stylesheets/scaffold.css +0 -80
  42. data/app/views/iro/alerts/edit.html.erb +0 -6
  43. data/app/views/iro/alerts/new.html.erb +0 -5
  44. data/app/views/iro/alerts/show.html.erb +0 -34
  45. data/app/views/iro/profiles/_form.html.erb +0 -32
  46. data/app/views/iro/profiles/edit.html.erb +0 -6
  47. data/app/views/iro/profiles/index.html.erb +0 -31
  48. data/app/views/iro/profiles/new.html.erb +0 -5
  49. data/app/views/iro/profiles/show.html.erb +0 -19
  50. /data/app/models/tda/{api.rb → stock.rb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ee2560d39aa4a4a279294e7611cc5e5564712c59931e0ae5f1d7ea91140aba5
4
- data.tar.gz: cf46d95a353f1097a78aa1009a9ffe17d6b305810def2cb440782fa46e59ac8a
3
+ metadata.gz: 179360dc9b7500f3725379c3c25e6a43c0f5b4bcf4fff1d16f1b23022fe1e8dc
4
+ data.tar.gz: e0800a507ec076cb0f819838c83a01d4ba75130b81fd4c86fe1e2fa1acdc905c
5
5
  SHA512:
6
- metadata.gz: 6ebc5bf69e74d48abd1cdcc2c097a5c59aea38c971bd0298850920e217576a90ea0d3520d423648af9df20591ccfa4f9cc637a280863b49ba48acd1cdd9aa78a
7
- data.tar.gz: 84c43a18c988669e34f19ecd961cebfe971795e1cc3ca628405d8a1c487b7805c8e443a38dd4a1b05f1c37c2cab304e8e412c98604cb6ff0e27d296deaa9c539
6
+ metadata.gz: '08052f61264a239d4e07bc14564e1f54c624d627c947f1ab7cce88a7e6ddffeaac64d92d91393c8f8842e0d7c8db236f1b0ec589a9b3e9251a00dd17a0f7232e'
7
+ data.tar.gz: 29772fd02c33118fb73797a981a4b03d0bbe561ab645623c4fd5abb0dc7fa0f2a6e9c7fd1bcb5cd918c873751d05210574ff38281e1ebfa72656357970dcb468
@@ -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