wco_models 3.1.0.265 → 3.1.0.266

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: 327c2ab838cce926d5afd9e979b7acb2979aa8e78d1745470ea29ccac2e81197
4
- data.tar.gz: 42615e28beeb55afbdf91eb592c58b22dae4a89d168e2ba17ce9046a7ac68857
3
+ metadata.gz: d52ff07afe73ec8c7240fbfb85a78a1cd4bf66c9db7c49fd69d5e7c3c56114aa
4
+ data.tar.gz: 33592a3dd04ab62d82c36d77070323735112bdb5966f8ba3009ff182c593f51e
5
5
  SHA512:
6
- metadata.gz: 9ca18a2f3190d96d1c8a2d9b62823886b8bb77870b22246a4af13f1f55081c65dd8bfc7b15e0db9fd232d0efc0968c7c4dd0ac8c9e0da1063c486b08fe2c5d9c
7
- data.tar.gz: 8c4c8a85bcd9087b837e6c70b42082967c9b2d502c9cc12651a946cceab10c6d85ca1d18646fa18f6b56862b51cd8436e9071a7eaa8bda059dbd6a1252cd65b3
6
+ metadata.gz: 88fc66fef4da9de8509ff2a46088229c73ea4041aa2aee67c1cd2771dbec93bafa164b6a6d39b7e312e3f86000b36cfc554fb33f9677b495fde357df60ed1739
7
+ data.tar.gz: 816df1b774e34f02dea1d1f23176a1ba5e0c00f84a1c04afb40084cd79af2671d1e28194b70ce8f90db6c239b672cc352ae8d27a00b9ac49e5f60977d49fad06
@@ -37,9 +37,6 @@ $enable-important-utilities: false;
37
37
  border-bottom: 1px solid gray;
38
38
  border-left: 1px solid gray;
39
39
 
40
- // border-top: 2px solid white;
41
- // border-left: 2px solid white;
42
-
43
40
  display: flex;
44
41
 
45
42
  margin-top: 1em;
@@ -10,17 +10,10 @@ class Iro::Option
10
10
 
11
11
  belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :strategies
12
12
  def ticker; stock.ticker; end
13
- # field :ticker
14
- # validates :ticker, presence: true
15
13
 
16
14
  CALL = 'CALL'
17
15
  PUT = 'PUT'
18
16
 
19
- ## for now, recompute every time
20
- # field :symbol
21
- ## each option can be a leg in a position, no uniqueness
22
- # validates :symbol, uniqueness: true, presence: true
23
-
24
17
  field :put_call, type: :string # 'PUT' or 'CALL'
25
18
  validates :put_call, presence: true
26
19
 
@@ -29,11 +22,6 @@ class Iro::Option
29
22
  field :strike, type: :float
30
23
  validates :strike, presence: true
31
24
 
32
- def to_s
33
- "#{symbol} :: #{expires_on.strftime('%Y-%m-%d')} #{put_call} #{strike}"
34
- end
35
-
36
-
37
25
  field :expires_on, type: :date
38
26
  validates :expires_on, presence: true
39
27
  def self.expirations_list full: false, n: 5
@@ -70,38 +58,13 @@ class Iro::Option
70
58
 
71
59
  field :last, type: :float
72
60
 
73
- ## for TDA
74
- ## "COST_030626C1030"
75
- def symbol_old
76
- if !self[:symbol]
77
- p_c_ = put_call == 'PUT' ? 'P' : 'C'
78
- strike_ = strike.to_i == strike ? strike.to_i : strike
79
- sym = "#{stock.ticker}_#{expires_on.strftime("%m%d%y")}#{p_c_}#{strike_}" # XYZ_011819P45
80
- self[:symbol] = sym
81
- save
82
- end
83
- self[:symbol]
84
- end
85
-
86
- ## for schwab
61
+ ## for schwab, eg:
87
62
  ## "COST 260306C01030000"
88
63
  def symbol
89
64
  p_c_ = put_call == 'PUT' ? 'P' : 'C'
90
65
  strike_ = format("%08d", (strike.to_f * 1000).round)
91
66
  sym = "#{stock.ticker.ljust(6)}#{expires_on.strftime("%y%m%d")}#{p_c_}#{strike_}"
92
67
  end
93
- =begin
94
- def symbol_trash ## it persists - which I dont do right now
95
- if !self[:symbol]
96
- p_c_ = put_call == 'PUT' ? 'P' : 'C'
97
- strike_ = format("%08d", (strike.to_f * 1000).round)
98
- sym = "#{stock.ticker.ljust(6)}#{expires_on.strftime("%y%m%d")}#{p_c_}#{strike_}"
99
- self[:symbol] = sym
100
- save
101
- end
102
- self[:symbol]
103
- end
104
- =end
105
68
 
106
69
  # before_save :sync, if: ->() { !Rails.env.test? } ## do not sync in test
107
70
  def sync
@@ -117,65 +80,7 @@ class Iro::Option
117
80
  self.save! ## 2026-02-19 this must be present.
118
81
  end
119
82
 
120
- def self.max_pain hash
121
- outs = {}
122
-
123
- %w| put call |.each do |contractType|
124
- dates = hash["#{contractType}ExpDateMap"]
125
- dates.each do |_date, strikes| ## _date="2023-02-10:5"
126
- date = _date.split(':')[0].to_date.to_s
127
- outs[date] ||= {
128
- 'all' => {},
129
- 'call' => {},
130
- 'put' => {},
131
- 'summary' => {},
132
- }
133
-
134
- strikes.each do |_strike, _v| ## _strike="18.5"
135
- strike = _strike.to_f
136
-
137
- ## calls
138
- mem_c = 0
139
- strikes.keys.reverse.each do |_key|
140
- if _key == _strike
141
- break
142
- end
143
- key = _key.to_f
144
- tmp = hash["callExpDateMap"][_date][_key][0]['openInterest'] * ( key - strike )
145
- mem_c += tmp
146
- end
147
- outs[date]['call'][_strike] = mem_c
148
-
149
- ## puts
150
- mem_p = 0
151
- strikes.keys.each do |_key|
152
- if _key == _strike
153
- break
154
- end
155
- key = _key.to_f
156
- tmp = hash["putExpDateMap"][_date][_key][0]['openInterest'] * ( strike - key )
157
- mem_p += tmp
158
- end
159
- outs[date]['put'][_strike] = mem_p
160
- outs[date]['all'][_strike] = mem_c + mem_p
161
-
162
- end
163
- end
164
- end
165
-
166
- ## compute summary
167
- outs.each do |date, types|
168
- all = types['all']
169
- outs[date]['summary'] = { 'value' => all.keys[0] }
170
- all.each do |strike, amount|
171
- if amount < all[ outs[date]['summary']['value'] ]
172
- outs[date]['summary']['value'] = strike
173
- end
174
- end
175
- end
176
-
177
- return outs
83
+ def to_s
84
+ "#{symbol} :: #{expires_on.strftime('%Y-%m-%d')} #{put_call} #{strike}"
178
85
  end
179
-
180
-
181
86
  end
@@ -0,0 +1,62 @@
1
+
2
+
3
+ def self.max_pain hash
4
+ outs = {}
5
+
6
+ %w| put call |.each do |contractType|
7
+ dates = hash["#{contractType}ExpDateMap"]
8
+ dates.each do |_date, strikes| ## _date="2023-02-10:5"
9
+ date = _date.split(':')[0].to_date.to_s
10
+ outs[date] ||= {
11
+ 'all' => {},
12
+ 'call' => {},
13
+ 'put' => {},
14
+ 'summary' => {},
15
+ }
16
+
17
+ strikes.each do |_strike, _v| ## _strike="18.5"
18
+ strike = _strike.to_f
19
+
20
+ ## calls
21
+ mem_c = 0
22
+ strikes.keys.reverse.each do |_key|
23
+ if _key == _strike
24
+ break
25
+ end
26
+ key = _key.to_f
27
+ tmp = hash["callExpDateMap"][_date][_key][0]['openInterest'] * ( key - strike )
28
+ mem_c += tmp
29
+ end
30
+ outs[date]['call'][_strike] = mem_c
31
+
32
+ ## puts
33
+ mem_p = 0
34
+ strikes.keys.each do |_key|
35
+ if _key == _strike
36
+ break
37
+ end
38
+ key = _key.to_f
39
+ tmp = hash["putExpDateMap"][_date][_key][0]['openInterest'] * ( strike - key )
40
+ mem_p += tmp
41
+ end
42
+ outs[date]['put'][_strike] = mem_p
43
+ outs[date]['all'][_strike] = mem_c + mem_p
44
+
45
+ end
46
+ end
47
+ end
48
+
49
+ ## compute summary
50
+ outs.each do |date, types|
51
+ all = types['all']
52
+ outs[date]['summary'] = { 'value' => all.keys[0] }
53
+ all.each do |strike, amount|
54
+ if amount < all[ outs[date]['summary']['value'] ]
55
+ outs[date]['summary']['value'] = strike
56
+ end
57
+ end
58
+ end
59
+
60
+ return outs
61
+ end
62
+
@@ -17,14 +17,22 @@ class Iro::Position
17
17
  STATUSES = [ nil, STATUS_CLOSED, STATUS_ACTIVE, STATUS_PREPARE, STATUS_PROPOSED, STATUS_PENDING ]
18
18
  field :status
19
19
  validates :status, presence: true
20
- scope :active, ->{ where( status: 'active' ) }
21
- field :schwab_status
20
+ scope :active, ->{ where( status: 'active' ) }
21
+ scope :proposed, ->{ where( status: 'proposed' ) }
22
+
22
23
 
23
24
  belongs_to :purse, class_name: 'Iro::Purse', inverse_of: :positions
24
25
  index({ purse_id: 1, ticker: 1 })
25
26
 
26
27
  belongs_to :stock, class_name: 'Iro::Stock', inverse_of: :positions
27
- delegate :ticker, to: :stock
28
+ field :ticker
29
+ def ticker
30
+ if !self[:ticker]
31
+ self[:ticker] = stock.ticker
32
+ self.save
33
+ end
34
+ self[:ticker]
35
+ end
28
36
 
29
37
  belongs_to :strategy, class_name: 'Iro::Strategy', inverse_of: :positions
30
38
  delegate :long_or_short, to: :strategy
@@ -77,6 +85,7 @@ class Iro::Position
77
85
  field :end_on
78
86
 
79
87
  field :schwab_order_id, type: :integer
88
+ field :schwab_status
80
89
 
81
90
  def begin_delta
82
91
  strategy.send("begin_delta_#{strategy.kind}", self)
@@ -126,6 +135,16 @@ class Iro::Position
126
135
  print '^'
127
136
  end
128
137
 
138
+
139
+ field :pending_price
140
+
141
+ ## place2 = credit-spread
142
+ def place2_price
143
+ pos = self
144
+ out = pos.inner.begin_price - pos.outer.begin_price
145
+ return out.round(2)
146
+ end
147
+
129
148
  def roll_price
130
149
  pos = self
131
150
  out = pos.autoprev.outer.end_price - pos.autoprev.inner.end_price + pos.inner.begin_price - pos.outer.begin_price
@@ -28,10 +28,7 @@ class Iro::Purse
28
28
  field :n_next_positions, type: :integer, default: 5
29
29
 
30
30
  field :available_amount, type: :float
31
- validates :available_amount, presence: true
32
- def available
33
- available_amount
34
- end
31
+ # validates :available_amount, presence: true
35
32
 
36
33
  def to_s
37
34
  slug
@@ -364,9 +364,6 @@ class Iro::Strategy
364
364
  end
365
365
 
366
366
 
367
- # def slug
368
- # "#{kind} #{stock}"
369
- # end
370
367
  def to_s
371
368
  "#{kind} #{stock} #{descr}"
372
369
  end
@@ -18,7 +18,7 @@ class Tda::Order
18
18
  },
19
19
  })
20
20
  puts! results, 'results'
21
- return results
21
+ return results.deep_symbolize_keys
22
22
  end
23
23
 
24
24
  ## not used - the hash is stored
@@ -33,6 +33,69 @@ class Tda::Order
33
33
  puts! results, 'results'
34
34
  end
35
35
 
36
+ def self.get_orders
37
+ profile = Wco::Profile.pi
38
+ today = Time.now.strftime("%Y-%m-%d")
39
+ results = self.get("/accounts/#{profile.schwab_account_hash}/orders", {
40
+ headers: {
41
+ accept: 'application/json',
42
+ Authorization: "Bearer #{profile[:schwab_exec_access_token]}",
43
+ },
44
+ query: {
45
+ fromEnteredTime: "#{today}T00:00:00Z",
46
+ toEnteredTime: "#{today}T23:59:59Z",
47
+ },
48
+ })
49
+ puts! results, 'get_orders() results'
50
+ puts! results.code, 'results.code'
51
+ return results
52
+ end
53
+
54
+ def self.cancel_order!( id )
55
+ profile = Wco::Profile.pi
56
+ results = self.delete("/accounts/#{profile.schwab_account_hash}/orders/#{id}", {
57
+ headers: {
58
+ accept: 'application/json',
59
+ Authorization: "Bearer #{profile[:schwab_exec_access_token]}",
60
+ },
61
+ })
62
+ puts! results, 'cancel_order!() results'
63
+ puts! results.code, 'results.code'
64
+ # if !results.code == '200'
65
+ # throw 'could not cancel order'
66
+ # end
67
+ end
68
+
69
+ def self.credit_spread_q pos
70
+ query = {
71
+ orderType: pos.place2_price > 0 ? "NET_CREDIT" : "NET_DEBIT",
72
+ session: "NORMAL",
73
+ duration: "DAY",
74
+ price: pos.pending_price,
75
+ orderStrategyType: "SINGLE",
76
+ orderLegCollection: [
77
+ ## open
78
+ {
79
+ instruction: "BUY_TO_OPEN",
80
+ quantity: pos.q,
81
+ instrument: {
82
+ symbol: pos.outer.symbol,
83
+ assetType: "OPTION",
84
+ },
85
+ },
86
+ {
87
+ instruction: "SELL_TO_OPEN",
88
+ quantity: pos.q,
89
+ instrument: {
90
+ symbol: pos.inner.symbol,
91
+ assetType: "OPTION",
92
+ },
93
+ },
94
+ ],
95
+ }
96
+ return query
97
+ end
98
+
36
99
  ## obsolete, I don't do covered calls anymore?
37
100
  def self.roll_covered_call_q pos
38
101
  roll_price = pos.inner.begin_price - pos.autoprev.inner.end_price
@@ -117,8 +180,8 @@ class Tda::Order
117
180
  return query
118
181
  end
119
182
 
120
- def self.place_order query
121
- puts! query, '#place_order'
183
+ def self.place_order! query
184
+ # puts! query, '#place_order'
122
185
 
123
186
  profile = Wco::Profile.pi
124
187
  results = self.post("/accounts/#{profile.schwab_account_hash}/orders", {
@@ -129,8 +192,14 @@ class Tda::Order
129
192
  },
130
193
  body: query.to_json,
131
194
  })
195
+ puts! results, 'place_order!() results'
196
+ puts! results.code, 'results.code'
197
+ # if 201 != results.code
198
+ # throw results
199
+ # end
132
200
  order_id = results.headers['location'].split('/').last
133
- return order_id
201
+ # response = JSON.parse results.body
202
+ return { schwab_order_id: order_id, schwab_status: 'WORKING' }
134
203
  end
135
204
 
136
205
  end
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.265
4
+ version: 3.1.0.266
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Pudeyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-07 00:00:00.000000000 Z
11
+ date: 2026-04-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ahoy_matey
@@ -477,6 +477,7 @@ files:
477
477
  - app/models/iro/datapoint.rb
478
478
  - app/models/iro/date.rb
479
479
  - app/models/iro/option.rb
480
+ - app/models/iro/option.rb-bk
480
481
  - app/models/iro/option_black_scholes.rb-bk
481
482
  - app/models/iro/position.rb
482
483
  - app/models/iro/priceitem.rb