Class: Schwab::Resources::Position

Inherits:
Base
  • Object
show all
Defined in:
lib/schwab/resources/position.rb

Overview

Resource wrapper for position objects Provides position-specific calculations and helper methods

Instance Method Summary collapse

Methods inherited from Base

#==, #[], #[]=, #attributes, #each, #empty?, field_types, #initialize, #inspect, #key?, #keys, #method_missing, #respond_to_missing?, set_field_type, #to_h, #to_s

Constructor Details

This class inherits a constructor from Schwab::Resources::Base

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Schwab::Resources::Base

Instance Method Details

#asset_typeString

Get the asset type



38
39
40
41
42
43
44
# File 'lib/schwab/resources/position.rb', line 38

def asset_type
  if self[:instrument]
    self[:instrument][:assetType] || self[:instrument][:asset_type]
  else
    self[:assetType] || self[:asset_type]
  end
end

#average_priceFloat? Also known as: cost_basis_per_share

Get the average price (cost basis per share)



70
71
72
# File 'lib/schwab/resources/position.rb', line 70

def average_price
  self[:averagePrice] || self[:average_price]
end

#call?Boolean?

Check if this is a call option



260
261
262
263
264
265
266
267
# File 'lib/schwab/resources/position.rb', line 260

def call?
  return false unless option?

  details = option_details
  return false unless details

  details[:option_type] == "CALL" || details[:option_type] == "call"
end

#cost_basisFloat Also known as: total_cost

Calculate the total cost basis



108
109
110
111
112
113
114
# File 'lib/schwab/resources/position.rb', line 108

def cost_basis
  if average_price && quantity
    (average_price * quantity.abs).round(2)
  else
    0.0
  end
end

#cost_per_contractFloat?

Calculate cost per contract for options



294
295
296
297
298
299
# File 'lib/schwab/resources/position.rb', line 294

def cost_per_contract
  return unless option? && cost_basis != 0 && quantity != 0

  contracts = quantity.abs
  cost_basis / contracts
end

#current_priceFloat? Also known as: market_price, last_price

Get the current price



78
79
80
81
82
83
84
85
86
# File 'lib/schwab/resources/position.rb', line 78

def current_price
  if self[:instrument] && self[:instrument][:lastPrice]
    self[:instrument][:lastPrice]
  elsif self[:quote]
    self[:quote][:last] || self[:quote][:mark]
  else
    self[:currentPrice] || self[:current_price] || self[:lastPrice] || self[:last_price]
  end
end

#cusipString

Get the CUSIP



49
50
51
52
53
54
55
# File 'lib/schwab/resources/position.rb', line 49

def cusip
  if self[:instrument]
    self[:instrument][:cusip]
  else
    self[:cusip]
  end
end

#day_pnlFloat? Also known as: todays_pnl, current_day_pnl

Get today’s P&L



138
139
140
141
142
143
# File 'lib/schwab/resources/position.rb', line 138

def day_pnl
  self[:currentDayProfitLoss] ||
    self[:current_day_profit_loss] ||
    self[:dayProfitLoss] ||
    self[:day_profit_loss]
end

#day_pnl_percentageFloat? Also known as: todays_pnl_percentage, current_day_pnl_percentage

Get today’s P&L percentage



150
151
152
153
154
155
# File 'lib/schwab/resources/position.rb', line 150

def day_pnl_percentage
  self[:currentDayProfitLossPercentage] ||
    self[:current_day_profit_loss_percentage] ||
    self[:dayProfitLossPercentage] ||
    self[:day_profit_loss_percentage]
end

#equity?Boolean

Check if this is an equity position



176
177
178
# File 'lib/schwab/resources/position.rb', line 176

def equity?
  asset_type == "EQUITY"
end

#expiration_dateString?

Get the expiration date for options



251
252
253
254
255
# File 'lib/schwab/resources/position.rb', line 251

def expiration_date
  return unless option?

  option_details[:expiration_date] if option_details
end

#instrumentHash?

Get the instrument details



211
212
213
# File 'lib/schwab/resources/position.rb', line 211

def instrument
  self[:instrument]
end

#long?Boolean

Check if this is a long position



162
163
164
# File 'lib/schwab/resources/position.rb', line 162

def long?
  quantity > 0
end

#losing?Boolean

Check if this is a losing position



197
198
199
# File 'lib/schwab/resources/position.rb', line 197

def losing?
  unrealized_pnl < 0
end

#maintenance_requirementFloat?

Get maintenance requirement for this position



204
205
206
# File 'lib/schwab/resources/position.rb', line 204

def maintenance_requirement
  self[:maintenanceRequirement] || self[:maintenance_requirement]
end

#market_valueFloat

Get the market value of the position



93
94
95
96
97
98
99
100
101
102
103
# File 'lib/schwab/resources/position.rb', line 93

def market_value
  value = self[:marketValue] || self[:market_value]
  return value.to_f if value

  # Calculate if not provided
  if current_price && quantity
    (current_price * quantity.abs).round(2)
  else
    0.0
  end
end

#option?Boolean

Check if this is an option position



183
184
185
# File 'lib/schwab/resources/position.rb', line 183

def option?
  asset_type == "OPTION"
end

#option_detailsHash?

Get option details if this is an option position



218
219
220
221
222
223
224
225
226
227
228
# File 'lib/schwab/resources/position.rb', line 218

def option_details
  return unless option? && instrument

  {
    underlying_symbol: instrument[:underlyingSymbol] || instrument[:underlying_symbol],
    strike_price: instrument[:strikePrice] || instrument[:strike_price],
    expiration_date: instrument[:expirationDate] || instrument[:expiration_date],
    option_type: instrument[:putCall] || instrument[:put_call] || instrument[:optionType] || instrument[:option_type],
    contract_size: instrument[:contractSize] || instrument[:contract_size] || 100,
  }
end

#profitable?Boolean

Check if this is a profitable position



190
191
192
# File 'lib/schwab/resources/position.rb', line 190

def profitable?
  unrealized_pnl > 0
end

#put?Boolean?

Check if this is a put option



272
273
274
275
276
277
278
279
# File 'lib/schwab/resources/position.rb', line 272

def put?
  return false unless option?

  details = option_details
  return false unless details

  details[:option_type] == "PUT" || details[:option_type] == "put"
end

#quantityFloat Also known as: net_quantity

Get the quantity (net of long and short)



60
61
62
63
64
# File 'lib/schwab/resources/position.rb', line 60

def quantity
  long_qty = (self[:longQuantity] || self[:long_quantity] || 0).to_f
  short_qty = (self[:shortQuantity] || self[:short_quantity] || 0).to_f
  long_qty - short_qty
end

#short?Boolean

Check if this is a short position



169
170
171
# File 'lib/schwab/resources/position.rb', line 169

def short?
  quantity < 0
end

#strike_priceFloat?

Get the strike price for options



242
243
244
245
246
# File 'lib/schwab/resources/position.rb', line 242

def strike_price
  return unless option?

  option_details[:strike_price] if option_details
end

#symbolString

Get the symbol



27
28
29
30
31
32
33
# File 'lib/schwab/resources/position.rb', line 27

def symbol
  if self[:instrument]
    self[:instrument][:symbol] || self[:instrument][:underlying_symbol]
  else
    self[:symbol]
  end
end

#to_display_stringString

Get formatted display string for the position



304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/schwab/resources/position.rb', line 304

def to_display_string
  if option?
    details = option_details
    if details
      "#{quantity.to_i} #{details[:underlying_symbol]} #{details[:strike_price]} #{details[:option_type]} #{details[:expiration_date]}"
    else
      "#{quantity.to_i} #{symbol}"
    end
  else
    "#{quantity} shares of #{symbol}"
  end
end

#underlying_symbolString?

Get the underlying symbol for options



233
234
235
236
237
# File 'lib/schwab/resources/position.rb', line 233

def underlying_symbol
  return unless option?

  option_details[:underlying_symbol] if option_details
end

#unrealized_pnlFloat Also known as: unrealized_profit_loss

Calculate unrealized P&L



120
121
122
# File 'lib/schwab/resources/position.rb', line 120

def unrealized_pnl
  market_value - cost_basis
end

#unrealized_pnl_percentageFloat? Also known as: unrealized_profit_loss_percentage

Calculate unrealized P&L percentage



128
129
130
131
132
# File 'lib/schwab/resources/position.rb', line 128

def unrealized_pnl_percentage
  return if cost_basis.zero?

  ((unrealized_pnl / cost_basis) * 100).round(2)
end

#value_per_contractFloat?

Calculate the value per contract for options



284
285
286
287
288
289
# File 'lib/schwab/resources/position.rb', line 284

def value_per_contract
  return unless option? && market_value && quantity != 0

  contracts = quantity.abs
  market_value / contracts
end