wco_models 3.1.0.184 → 3.1.0.188
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/README.txt +10 -1
- data/app/models/iro/alert.rb +63 -0
- data/app/models/iro/datapoint.rb +187 -0
- data/app/models/iro/date.rb +10 -0
- data/app/models/iro/option.rb +154 -0
- data/app/models/iro/option_black_scholes.rb +149 -0
- data/app/models/iro/position.rb +304 -0
- data/app/models/iro/priceitem.rb +93 -0
- data/app/models/iro/purse.rb +71 -0
- data/app/models/iro/stock.rb +141 -0
- data/app/models/iro/strategy.rb +284 -0
- data/app/models/wco/profile.rb +3 -0
- data/app/models/wco_email/message_stub.rb +2 -5
- data/app/views/wco/profiles/_form.haml +10 -0
- data/config/initializers/00_s3.rb +13 -0
- data/config/initializers/00_s3.rb-example +13 -0
- data/config/initializers/08_integrations.rb +9 -0
- data/config/initializers/08_integrations.rb-example +6 -0
- metadata +16 -2
@@ -0,0 +1,284 @@
|
|
1
|
+
|
2
|
+
class Iro::Strategy
|
3
|
+
include Mongoid::Document
|
4
|
+
include Mongoid::Timestamps
|
5
|
+
include Mongoid::Paranoia
|
6
|
+
store_in collection: 'iro_strategies'
|
7
|
+
|
8
|
+
# field :slug
|
9
|
+
# validates :slug, presence: true, uniqueness: true
|
10
|
+
|
11
|
+
field :description
|
12
|
+
|
13
|
+
LONG = 'long'
|
14
|
+
SHORT = 'short'
|
15
|
+
field :long_or_short, type: :string
|
16
|
+
validates :long_or_short, presence: true
|
17
|
+
|
18
|
+
CREDIT = 'credit'
|
19
|
+
DEBIT = 'debit'
|
20
|
+
field :credit_or_debit, type: :string
|
21
|
+
validates :credit_or_debit, presence: true
|
22
|
+
|
23
|
+
|
24
|
+
has_many :positions, class_name: 'Iro::Position', inverse_of: :strategy
|
25
|
+
has_one :next_position, class_name: 'Iro::Position', inverse_of: :next_strategy
|
26
|
+
belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :strategies
|
27
|
+
# has_and_belongs_to_many :purses, class_name: 'Iro::Purse', inverse_of: :strategies
|
28
|
+
|
29
|
+
# KIND_COVERED_CALL = 'covered_call'
|
30
|
+
# KIND_IRON_CONDOR = 'iron_condor'
|
31
|
+
# KIND_LONG_CREDIT_PUT_SPREAD = 'long_credit_put_spread'
|
32
|
+
# KIND_LONG_DEBIT_CALL_SPREAD = 'long_debit_call_spread'
|
33
|
+
# KIND_SHORT_CREDIT_CALL_SPREAD = 'short_credit_call_spread'
|
34
|
+
# KIND_SHORT_DEBIT_PUT_SPREAD = 'short_debit_put_spread'
|
35
|
+
# KINDS = [ nil,
|
36
|
+
# KIND_COVERED_CALL,
|
37
|
+
# KIND_IRON_CONDOR,
|
38
|
+
# KIND_LONG_CREDIT_PUT_SPREAD,
|
39
|
+
# KIND_LONG_DEBIT_CALL_SPREAD,
|
40
|
+
# KIND_SHORT_CREDIT_CALL_SPREAD,
|
41
|
+
# KIND_SHORT_DEBIT_PUT_SPREAD,
|
42
|
+
# ];
|
43
|
+
KIND_SPREAD = 'spread'
|
44
|
+
KIND_WHEEL = 'wheel'
|
45
|
+
field :kind
|
46
|
+
|
47
|
+
def put_call
|
48
|
+
case kind
|
49
|
+
# when Iro::Strategy::KIND_LONG_CREDIT_PUT_SPREAD
|
50
|
+
# put_call = 'PUT'
|
51
|
+
# when Iro::Strategy::KIND_LONG_DEBIT_CALL_SPREAD
|
52
|
+
# put_call = 'CALL'
|
53
|
+
# when Iro::Strategy::KIND_SHORT_CREDIT_CALL_SPREAD
|
54
|
+
# put_call = 'CALL'
|
55
|
+
# when Iro::Strategy::KIND_SHORT_DEBIT_PUT_SPREAD
|
56
|
+
# put_call = 'PUT'
|
57
|
+
# when Iro::Strategy::KIND_COVERED_CALL
|
58
|
+
# put_call = 'CALL'
|
59
|
+
when Iro::Strategy::KIND_SPREAD
|
60
|
+
if credit_or_debit == CREDIT
|
61
|
+
if long_or_short == LONG
|
62
|
+
'PUT'
|
63
|
+
elsif long_or_short == SHORT
|
64
|
+
'CALL'
|
65
|
+
else
|
66
|
+
throw 'zz5 - should never happen'
|
67
|
+
end
|
68
|
+
else
|
69
|
+
throw 'zz6 - debit spreads are not implemented'
|
70
|
+
end
|
71
|
+
when Iro::Strategy::KIND_WHEEL
|
72
|
+
'CALL'
|
73
|
+
else
|
74
|
+
throw 'zz9 - this should never happen'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
field :threshold_buffer_above_water, type: :float
|
79
|
+
field :threshold_delta, type: :float
|
80
|
+
field :threshold_netp, type: :float
|
81
|
+
field :threshold_dte, type: :integer, default: 1
|
82
|
+
|
83
|
+
field :next_inner_delta, type: :float
|
84
|
+
field :next_inner_strike, type: :float
|
85
|
+
field :next_outer_delta, type: :float
|
86
|
+
field :next_outer_strike, type: :float
|
87
|
+
field :next_spread_amount, type: :float # e.g. $20 for a $2000 NVDA spread
|
88
|
+
field :next_buffer_above_water, type: :float
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
def begin_delta_wheel p
|
96
|
+
p.inner.begin_delta
|
97
|
+
end
|
98
|
+
def begin_delta_spread p
|
99
|
+
p.inner.begin_delta - p.outer.begin_delta
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def breakeven_covered_call p
|
104
|
+
p.inner.strike + p.inner.begin_price
|
105
|
+
end
|
106
|
+
def breakeven_long_debit_call_spread p
|
107
|
+
p.inner.strike - p.max_gain
|
108
|
+
end
|
109
|
+
alias_method :breakeven_short_debit_put_spread, :breakeven_long_debit_call_spread
|
110
|
+
|
111
|
+
|
112
|
+
def end_delta_wheel p
|
113
|
+
p.inner.end_delta
|
114
|
+
end
|
115
|
+
def end_delta_spread p
|
116
|
+
p.inner.end_delta - p.outer.end_delta
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
# def max_gain_covered_call p
|
121
|
+
# p.inner.begin_price * 100 - 0.66 # @TODO: is this *100 really?
|
122
|
+
# end
|
123
|
+
# # def max_gain_long_credit_put_spread p
|
124
|
+
# ## 100 * disallowed for gameui
|
125
|
+
# p.inner.begin_price - p.outer.begin_price
|
126
|
+
# end
|
127
|
+
# def max_gain_long_debit_call_spread p
|
128
|
+
# ## 100 * disallowed for gameui
|
129
|
+
# ( p.inner.strike - p.outer.strike - p.outer.begin_price + p.inner.begin_price ) # - 2*0.66
|
130
|
+
# end
|
131
|
+
# def max_gain_short_credit_call_spread p
|
132
|
+
# p.inner.begin_price - p.outer.begin_price
|
133
|
+
# end
|
134
|
+
# def max_gain_short_debit_put_spread p
|
135
|
+
# ## 100 * disallowed for gameui
|
136
|
+
# ( p.outer.strike - p.inner.strike - p.outer.begin_price + p.inner.begin_price ) # - 2*0.66
|
137
|
+
# end
|
138
|
+
def max_gain_spread p
|
139
|
+
## 100 * disallowed for gameui
|
140
|
+
( p.outer.strike - p.inner.strike ).abs - p.outer.begin_price + p.inner.begin_price # - 2*0.66
|
141
|
+
end
|
142
|
+
def max_gain_wheel p
|
143
|
+
p.inner.begin_price * 100 - 0.66 # @TODO: is this *100 really?
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
# def max_loss_covered_call p
|
148
|
+
# p.inner.begin_price*10 # just suppose 10,000%
|
149
|
+
# end
|
150
|
+
# def max_loss_long_credit_put_spread p
|
151
|
+
# out = p.inner.strike - p.outer.strike
|
152
|
+
# end
|
153
|
+
# def max_loss_long_debit_call_spread p
|
154
|
+
# out = p.outer.strike - p.inner.strike
|
155
|
+
# end
|
156
|
+
# def max_loss_short_debit_put_spread p # different
|
157
|
+
# out = p.inner.strike - p.outer.strike
|
158
|
+
# end
|
159
|
+
# def max_loss_short_credit_call_spread p
|
160
|
+
# out = p.outer.strike - p.inner.strike
|
161
|
+
# end
|
162
|
+
def max_loss_spread p
|
163
|
+
( p.outer.strike - p.inner.strike ).abs
|
164
|
+
end
|
165
|
+
def max_loss_wheel p
|
166
|
+
p.inner.begin_price*10 # just suppose 10,000%
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
def net_amount_spread p
|
172
|
+
p.inner.begin_price - p.inner.end_price
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
## 2024-05-09 @TODO
|
177
|
+
def next_inner_strike_on expires_on
|
178
|
+
outs = Tda::Option.get_quotes({
|
179
|
+
contractType: put_call,
|
180
|
+
expirationDate: expires_on,
|
181
|
+
ticker: stock.ticker,
|
182
|
+
})
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
##
|
188
|
+
## decisions
|
189
|
+
##
|
190
|
+
|
191
|
+
def calc_rollp_covered_call p
|
192
|
+
|
193
|
+
if ( p.expires_on.to_date - Time.now.to_date ).to_i < 1
|
194
|
+
return [ 0.99, '0 DTE, must exit' ]
|
195
|
+
end
|
196
|
+
|
197
|
+
if ( stock.last - buffer_above_water ) < p.inner.strike
|
198
|
+
return [ 0.98, "Last #{'%.2f' % stock.last} is " +
|
199
|
+
"#{'%.2f' % [p.inner.strike + buffer_above_water - stock.last]} " +
|
200
|
+
"below #{'%.2f' % [p.inner.strike + buffer_above_water]} water" ]
|
201
|
+
end
|
202
|
+
|
203
|
+
if p.inner.end_delta < threshold_delta
|
204
|
+
return [ 0.61, "Delta #{p.inner.end_delta} is lower than #{threshold_delta} threshold." ]
|
205
|
+
end
|
206
|
+
|
207
|
+
if 1 - p.inner.end_price/p.inner.begin_price > threshold_netp
|
208
|
+
return [ 0.51, "made enough #{'%.02f' % [(1.0 - p.inner.end_price/p.inner.begin_price )*100]}% profit." ]
|
209
|
+
end
|
210
|
+
|
211
|
+
return [ 0.33, '-' ]
|
212
|
+
end
|
213
|
+
|
214
|
+
## @TODO
|
215
|
+
def calc_rollp_long_debit_call_spread p
|
216
|
+
|
217
|
+
if ( p.expires_on.to_date - Time.now.to_date ).to_i < 1
|
218
|
+
return [ 0.99, '0 DTE, must exit' ]
|
219
|
+
end
|
220
|
+
if ( p.expires_on.to_date - Time.now.to_date ).to_i < 2
|
221
|
+
return [ 0.99, '1 DTE, must exit' ]
|
222
|
+
end
|
223
|
+
|
224
|
+
if ( stock.last - buffer_above_water ) < p.inner.strike
|
225
|
+
return [ 0.95, "Last #{'%.2f' % stock.last} is " +
|
226
|
+
"#{'%.2f' % [stock.last - p.inner.strike - buffer_above_water]} " +
|
227
|
+
"below #{'%.2f' % [p.inner.strike + buffer_above_water]} water" ]
|
228
|
+
end
|
229
|
+
|
230
|
+
if p.inner.end_delta < threshold_delta
|
231
|
+
return [ 0.79, "Delta #{p.inner.end_delta} is lower than #{threshold_delta} threshold." ]
|
232
|
+
end
|
233
|
+
|
234
|
+
if 1 - p.inner.end_price/p.inner.begin_price > threshold_netp
|
235
|
+
return [ 0.51, "made enough #{'%.02f' % [(1.0 - p.inner.end_price/p.inner.begin_price )*100]}% profit^" ]
|
236
|
+
end
|
237
|
+
|
238
|
+
return [ 0.33, '-' ]
|
239
|
+
end
|
240
|
+
|
241
|
+
## @TODO
|
242
|
+
def calc_rollp_short_debit_put_spread p
|
243
|
+
|
244
|
+
if ( p.expires_on.to_date - Time.now.to_date ).to_i <= min_dte
|
245
|
+
return [ 0.99, "< #{min_dte}DTE, must exit" ]
|
246
|
+
end
|
247
|
+
|
248
|
+
if stock.last + buffer_above_water > p.inner.strike
|
249
|
+
return [ 0.98, "Last #{'%.2f' % stock.last} is " +
|
250
|
+
"#{'%.2f' % [stock.last + buffer_above_water - p.inner.strike]} " +
|
251
|
+
"above #{'%.2f' % [p.inner.strike - buffer_above_water]} water" ]
|
252
|
+
end
|
253
|
+
|
254
|
+
if p.inner.end_delta.abs < threshold_delta.abs
|
255
|
+
return [ 0.79, "Delta #{p.inner.end_delta} is lower than #{threshold_delta} threshold." ]
|
256
|
+
end
|
257
|
+
|
258
|
+
if p.net_percent > threshold_netp
|
259
|
+
return [ 0.51, "made enough #{'%.0f' % [p.net_percent*100]}% > #{"%.2f" % [threshold_netp*100]}% profit," ]
|
260
|
+
end
|
261
|
+
|
262
|
+
return [ 0.33, '-' ]
|
263
|
+
end
|
264
|
+
|
265
|
+
|
266
|
+
## scopes
|
267
|
+
|
268
|
+
def self.for_ticker ticker
|
269
|
+
where( ticker: ticker )
|
270
|
+
end
|
271
|
+
|
272
|
+
|
273
|
+
def slug
|
274
|
+
"#{long_or_short} #{credit_or_debit} #{kind} #{stock}"
|
275
|
+
end
|
276
|
+
def to_s
|
277
|
+
slug
|
278
|
+
end
|
279
|
+
def self.list long_or_short = nil
|
280
|
+
these = long_or_short ? where( long_or_short: long_or_short ) : all
|
281
|
+
[[nil,nil]] + these.map { |ttt| [ ttt, ttt.id ] }
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
data/app/models/wco/profile.rb
CHANGED
@@ -24,6 +24,9 @@ class Wco::Profile
|
|
24
24
|
has_many :newsitems, class_name: 'Wco::Newsitem'
|
25
25
|
has_and_belongs_to_many :shared_galleries, class_name: 'Wco::Gallery', inverse_of: :shared_profiles
|
26
26
|
|
27
|
+
field :sentiment, default: Iro::Stock::LONG_OR_SHORT
|
28
|
+
field :sentiment_num, default: 0 # 1 is very long, -1 is very short
|
29
|
+
|
27
30
|
ROLE_ADMIN = 'admin'
|
28
31
|
ROLE_GUY = 'guy'
|
29
32
|
ROLES = [ ROLE_ADMIN, ROLE_GUY ]
|
@@ -42,16 +42,13 @@ class WcoEmail::MessageStub
|
|
42
42
|
AOL
|
43
43
|
|
44
44
|
def do_process
|
45
|
-
@client ||= Aws::S3::Client.new(
|
46
|
-
region: ::S3_CREDENTIALS[:region_ses],
|
47
|
-
access_key_id: ::S3_CREDENTIALS[:access_key_id_ses],
|
48
|
-
secret_access_key: ::S3_CREDENTIALS[:secret_access_key_ses],
|
49
|
-
})
|
45
|
+
@client ||= Aws::S3::Client.new(::SES_S3_CREDENTIALS)
|
50
46
|
stub = self
|
51
47
|
|
52
48
|
raw = @client.get_object( bucket: stub.bucket, key: stub.object_key ).body.read
|
53
49
|
raw = raw.encode('utf-8', invalid: :replace, undef: :replace, replace: '_' )
|
54
50
|
the_mail = Mail.new( raw )
|
51
|
+
puts! the_mail, 'the_mail'
|
55
52
|
|
56
53
|
message_id = the_mail.header['message-id']&.decoded
|
57
54
|
message_id ||= "#{the_mail.date&.iso8601}::#{the_mail.from}"
|
@@ -9,5 +9,15 @@
|
|
9
9
|
%label role
|
10
10
|
= f.select :role, options_for_select(Wco::Profile.roles_list, selected: profile.role )
|
11
11
|
|
12
|
+
.field
|
13
|
+
%label schwab_access_token
|
14
|
+
= f.text_field :schwab_access_token
|
15
|
+
.field
|
16
|
+
%label schwab_refresh_token
|
17
|
+
= f.text_field :schwab_refresh_token
|
18
|
+
.field
|
19
|
+
%label schwab_access_token
|
20
|
+
= f.text_field :schwab_id_token
|
21
|
+
|
12
22
|
.actions
|
13
23
|
= f.submit 'Go'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
::S3_CREDENTIALS ||= {
|
2
|
+
## user:
|
3
|
+
access_key_id: "",
|
4
|
+
secret_access_key: "",
|
5
|
+
bucket: "wco-email-development",
|
6
|
+
region: 'us-east-1',
|
7
|
+
}
|
8
|
+
|
9
|
+
::SES_S3_CREDENTIALS ||= {
|
10
|
+
endpoint: "http://localhost:4566/",
|
11
|
+
force_path_style: true,
|
12
|
+
}
|
13
|
+
::SES_S3_BUCKET ||= "wco-email-ses-development"
|
@@ -0,0 +1,13 @@
|
|
1
|
+
::S3_CREDENTIALS ||= {
|
2
|
+
## user:
|
3
|
+
access_key_id: "",
|
4
|
+
secret_access_key: "",
|
5
|
+
bucket: "wco-email-development",
|
6
|
+
region: 'us-east-1',
|
7
|
+
}
|
8
|
+
|
9
|
+
::SES_S3_CREDENTIALS ||= {
|
10
|
+
endpoint: "http://localhost:4566/",
|
11
|
+
force_path_style: true,
|
12
|
+
}
|
13
|
+
::SES_S3_BUCKET ||= "wco-email-ses-development"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wco_models
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.0.
|
4
|
+
version: 3.1.0.188
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Pudeyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-11-
|
11
|
+
date: 2024-11-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ahoy_matey
|
@@ -458,6 +458,16 @@ files:
|
|
458
458
|
- app/models/ability.rb
|
459
459
|
- app/models/ahoy/event.rb
|
460
460
|
- app/models/ahoy/visit.rb
|
461
|
+
- app/models/iro/alert.rb
|
462
|
+
- app/models/iro/datapoint.rb
|
463
|
+
- app/models/iro/date.rb
|
464
|
+
- app/models/iro/option.rb
|
465
|
+
- app/models/iro/option_black_scholes.rb
|
466
|
+
- app/models/iro/position.rb
|
467
|
+
- app/models/iro/priceitem.rb
|
468
|
+
- app/models/iro/purse.rb
|
469
|
+
- app/models/iro/stock.rb
|
470
|
+
- app/models/iro/strategy.rb
|
461
471
|
- app/models/wco/asset.rb
|
462
472
|
- app/models/wco/gallery.rb
|
463
473
|
- app/models/wco/headline.rb
|
@@ -700,6 +710,10 @@ files:
|
|
700
710
|
- app/views/wco_hosting/ecs_task_definitions/hw1.json
|
701
711
|
- app/views/wco_hosting/scripts/create_volume.erb
|
702
712
|
- app/views/wco_hosting/scripts/nginx_site.conf.erb
|
713
|
+
- config/initializers/00_s3.rb
|
714
|
+
- config/initializers/00_s3.rb-example
|
715
|
+
- config/initializers/08_integrations.rb
|
716
|
+
- config/initializers/08_integrations.rb-example
|
703
717
|
- config/initializers/ahoy.rb
|
704
718
|
- config/initializers/assets.rb
|
705
719
|
- config/routes.rb
|