wco_models 3.1.0.266 → 3.1.0.267

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d52ff07afe73ec8c7240fbfb85a78a1cd4bf66c9db7c49fd69d5e7c3c56114aa
4
- data.tar.gz: 33592a3dd04ab62d82c36d77070323735112bdb5966f8ba3009ff182c593f51e
3
+ metadata.gz: a1f54c396bd801b8243d24de86159a104d390d1b74ce79bd12c3bde3bda2d682
4
+ data.tar.gz: 137492819d59dc6cffb3a220f74f4352970dd69a3d8a01a585e3f17c7260dd1c
5
5
  SHA512:
6
- metadata.gz: 88fc66fef4da9de8509ff2a46088229c73ea4041aa2aee67c1cd2771dbec93bafa164b6a6d39b7e312e3f86000b36cfc554fb33f9677b495fde357df60ed1739
7
- data.tar.gz: 816df1b774e34f02dea1d1f23176a1ba5e0c00f84a1c04afb40084cd79af2671d1e28194b70ce8f90db6c239b672cc352ae8d27a00b9ac49e5f60977d49fad06
6
+ metadata.gz: b8b9b3d27b172ad9094d5231865e2864881696718bb014a4ae7c73405a5e58eb4df313ef1340a14bbc6109293b1656e060493d0127eb00988bb9f8400ac92d7f
7
+ data.tar.gz: cc019d6173c28f78dd506300a8bd692086d9d84752e2744dfa547d03d61dc3a47513af1be09653e588200ed444d0528bf5c940294d3c65e2b7e64a8d17a3139e
@@ -66,6 +66,34 @@ class Iro::Option
66
66
  sym = "#{stock.ticker.ljust(6)}#{expires_on.strftime("%y%m%d")}#{p_c_}#{strike_}"
67
67
  end
68
68
 
69
+ =begin
70
+ symbol = "META 260424P00500000"
71
+ =end
72
+ def self.symbol_to_h symbol
73
+ ticker = symbol[0,6].strip
74
+ date_str = symbol[6,6]
75
+ type = symbol[12] == 'P' ? 'PUT' : 'CALL'
76
+ strike_str = symbol[13,8]
77
+ expires_on = Date.strptime(date_str, "%y%m%d")
78
+ strike = strike_str.to_i / 1000.0
79
+ return {
80
+ ticker: ticker,
81
+ strike: strike,
82
+ put_call: type,
83
+ expires_on: expires_on,
84
+ }
85
+ end
86
+
87
+ def matches_h h
88
+ if h[:put_call] == put_call &&
89
+ h[:strike] == strike &&
90
+ h[:expires_on] == expires_on
91
+ return true
92
+ else
93
+ return false
94
+ end
95
+ end
96
+
69
97
  # before_save :sync, if: ->() { !Rails.env.test? } ## do not sync in test
70
98
  def sync
71
99
  out = Tda::Option.get_quote({
@@ -7,7 +7,6 @@ class Iro::Position
7
7
 
8
8
  field :next_gain_loss_amount, type: :float
9
9
 
10
-
11
10
  STATUS_ACTIVE = 'active'
12
11
  STATUS_CLOSED = 'closed'
13
12
  STATUS_PREPARE = 'prepare'
@@ -20,6 +19,15 @@ class Iro::Position
20
19
  scope :active, ->{ where( status: 'active' ) }
21
20
  scope :proposed, ->{ where( status: 'proposed' ) }
22
21
 
22
+ def status_label st
23
+ labels = {}
24
+ labels[STATUS_PROPOSED] = 'Selected.'
25
+ return labels[st] || st
26
+ end
27
+
28
+ INTENT_CLOSE = 'close.'
29
+ INTENTS = [ nil, INTENT_CLOSE ]
30
+ field :intent
23
31
 
24
32
  belongs_to :purse, class_name: 'Iro::Purse', inverse_of: :positions
25
33
  index({ purse_id: 1, ticker: 1 })
@@ -138,6 +146,13 @@ class Iro::Position
138
146
 
139
147
  field :pending_price
140
148
 
149
+ ## credit spread only
150
+ def close_price
151
+ pos = self
152
+ out = pos.outer.end_price - pos.inner.end_price
153
+ return out.round(2)
154
+ end
155
+
141
156
  ## place2 = credit-spread
142
157
  def place2_price
143
158
  pos = self
@@ -207,8 +222,6 @@ class Iro::Position
207
222
  def calc_rollp
208
223
  pos = self
209
224
  pos.next_reasons = []
210
- # pos.next_symbol = nil
211
- # pos.next_delta = nil
212
225
 
213
226
  out = strategy.send("calc_rollp_#{strategy.kind}", pos )
214
227
 
@@ -73,12 +73,43 @@ class ::Iro::Stock
73
73
 
74
74
  =end
75
75
  field :volatility, type: :float
76
+ field :volatility_annual
77
+ field :volatility_monthly
78
+ field :volatility_daily
76
79
  def volatility duration: 1.year, recompute: false
77
80
  if self[:volatility]
78
81
  if !recompute
79
82
  return self[:volatility]
80
83
  end
81
84
  end
85
+ stock = self
86
+ begin_on = Time.now - duration
87
+ points = ::Iro::Datapoint.where( kind: 'STOCK', symbol: stock.ticker,
88
+ :date.gte => begin_on,
89
+ ).order_by( date: :asc )
90
+
91
+ returns = []
92
+ points.each_cons(2) do |prev, curr|
93
+ returns << Math.log(curr.value / prev.value)
94
+ end
95
+ # puts! returns, 'returns'
96
+
97
+ mean = returns.sum / returns.size
98
+ variance = returns.sum { |r| (r - mean) ** 2 } / (returns.size - 1)
99
+
100
+ daily_vol = Math.sqrt(variance)
101
+ monthly_vol = daily_vol * Math.sqrt(21)
102
+ annual_vol = daily_vol * Math.sqrt(252)
103
+
104
+ self.update(volatility_annual: annual_vol, volatility_monthly: monthly_vol, volatility_daily: daily_vol)
105
+ annual_vol
106
+ end
107
+ def volatility_old duration: 1.year, recompute: false
108
+ if self[:volatility]
109
+ if !recompute
110
+ return self[:volatility]
111
+ end
112
+ end
82
113
 
83
114
  stock = self
84
115
  begin_on = Time.now - duration - 1.day
@@ -107,10 +138,8 @@ class ::Iro::Stock
107
138
 
108
139
  # n_periods = begin_on.to_date.business_days_until( Date.today )
109
140
  out = Math.sqrt( sum_of_sq )*sqrt( n )
110
- adjustment = 2.0
111
- out = out * adjustment
112
141
  puts! out, 'volatility (adjusted)'
113
- self.update volatility: out
142
+ self.update( volatility: out, volatility_annual: out )
114
143
  return out
115
144
  end
116
145
 
@@ -147,7 +176,7 @@ class ::Iro::Stock
147
176
  date_from ||= Time.now - 1.year - 1.week
148
177
  date_to ||= date_from + 180.days
149
178
  date_from = date_from.strftime('%Y-%m-%d')
150
- date_to = date_to.strftime('%Y-%m-%d')
179
+ date_to = date_to.strftime('%Y-%m-%d')
151
180
  puts! [ticker, date_from, date_to], "ticker,date_from,date_to"
152
181
  outs = HTTParty.get("https://api.stockdata.org/v1/data/eod?symbols=#{ticker}&date_from=#{date_from}&date_to=#{date_to}&api_token=#{STOCKDATA_ORG_KEY}")
153
182
  outs['data'].each do |datum|
@@ -66,6 +66,39 @@ class Tda::Order
66
66
  # end
67
67
  end
68
68
 
69
+
70
+ def self.close_credit_spread_q pos
71
+ query = {
72
+ orderType: pos.pending_price > 0 ? "NET_CREDIT" : "NET_DEBIT",
73
+ session: "NORMAL",
74
+ duration: "DAY",
75
+ price: pos.pending_price.abs,
76
+ orderStrategyType: "SINGLE",
77
+ orderLegCollection: [
78
+ ## close
79
+ {
80
+ instruction: "BUY_TO_CLOSE",
81
+ quantity: pos.q,
82
+ instrument: {
83
+ symbol: pos.inner.symbol,
84
+ assetType: "OPTION",
85
+ },
86
+ },
87
+ {
88
+ instruction: "SELL_TO_CLOSE",
89
+ quantity: pos.q,
90
+ instrument: {
91
+ symbol: pos.outer.symbol,
92
+ assetType: "OPTION",
93
+ },
94
+ },
95
+
96
+ ],
97
+ }
98
+ return query
99
+ end
100
+
101
+ ## open credit spread?!
69
102
  def self.credit_spread_q pos
70
103
  query = {
71
104
  orderType: pos.place2_price > 0 ? "NET_CREDIT" : "NET_DEBIT",
@@ -96,6 +129,30 @@ class Tda::Order
96
129
  return query
97
130
  end
98
131
 
132
+
133
+ def self.place_order! query
134
+ # puts! query, '#place_order'
135
+
136
+ profile = Wco::Profile.pi
137
+ results = self.post("/accounts/#{profile.schwab_account_hash}/orders", {
138
+ headers: {
139
+ 'content-type' => 'application/json',
140
+ accept: 'application/json',
141
+ Authorization: "Bearer #{profile[:schwab_exec_access_token]}",
142
+ },
143
+ body: query.to_json,
144
+ })
145
+ puts! results, 'place_order!() results'
146
+ puts! results.code, 'results.code'
147
+ # if 201 != results.code
148
+ # throw results
149
+ # end
150
+ order_id = results.headers['location'].split('/').last
151
+ # response = JSON.parse results.body
152
+ return { schwab_order_id: order_id, schwab_status: 'WORKING' }
153
+ end
154
+
155
+
99
156
  ## obsolete, I don't do covered calls anymore?
100
157
  def self.roll_covered_call_q pos
101
158
  roll_price = pos.inner.begin_price - pos.autoprev.inner.end_price
@@ -180,26 +237,4 @@ class Tda::Order
180
237
  return query
181
238
  end
182
239
 
183
- def self.place_order! query
184
- # puts! query, '#place_order'
185
-
186
- profile = Wco::Profile.pi
187
- results = self.post("/accounts/#{profile.schwab_account_hash}/orders", {
188
- headers: {
189
- 'content-type' => 'application/json',
190
- accept: 'application/json',
191
- Authorization: "Bearer #{profile[:schwab_exec_access_token]}",
192
- },
193
- body: query.to_json,
194
- })
195
- puts! results, 'place_order!() results'
196
- puts! results.code, 'results.code'
197
- # if 201 != results.code
198
- # throw results
199
- # end
200
- order_id = results.headers['location'].split('/').last
201
- # response = JSON.parse results.body
202
- return { schwab_order_id: order_id, schwab_status: 'WORKING' }
203
- end
204
-
205
240
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wco_models
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0.266
4
+ version: 3.1.0.267
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Pudeyev