Class: Schwab::Resources::Order

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

Overview

Resource wrapper for order objects Provides order-specific helper methods and status checking

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

#account_idString

Get account ID

Returns:

  • (String)

    The account ID



33
34
35
# File 'lib/schwab/resources/order.rb', line 33

def 
  self[:accountNumber] || self[:account_number] || self[:accountId] || self[:account_id]
end

#activation_priceFloat?

Get activation price (for trailing stops)

Returns:

  • (Float, nil)

    The activation price



138
139
140
# File 'lib/schwab/resources/order.rb', line 138

def activation_price
  self[:activationPrice] || self[:activation_price]
end

#active?Boolean Also known as: working?, open?

Check if order is active/working

Returns:

  • (Boolean)

    True if active



224
225
226
# File 'lib/schwab/resources/order.rb', line 224

def active?
  ["ACCEPTED", "WORKING", "QUEUED"].include?(status&.upcase)
end

#buy?Boolean

Check if buy order

Returns:

  • (Boolean)

    True if buy



322
323
324
325
# File 'lib/schwab/resources/order.rb', line 322

def buy?
  inst = instruction&.upcase
  ["BUY", "BUY_TO_COVER", "BUY_TO_OPEN", "BUY_TO_CLOSE"].include?(inst)
end

#cancelled?Boolean Also known as: canceled?

Check if order is cancelled

Returns:

  • (Boolean)

    True if cancelled



247
248
249
# File 'lib/schwab/resources/order.rb', line 247

def cancelled?
  ["CANCELED", "CANCELLED", "PENDING_CANCEL"].include?(status&.upcase)
end

#child_ordersArray<Order>

Get child orders

Returns:

  • (Array<Order>)

    Array of child orders



166
167
168
169
170
171
# File 'lib/schwab/resources/order.rb', line 166

def child_orders
  children = self[:childOrderStrategies] || self[:child_order_strategies] || []
  children.map do |child_data|
    child_data.is_a?(Order) ? child_data : Order.new(child_data, client)
  end
end

#close_timeTime, ...

Get close time (when order was filled/cancelled)

Returns:

  • (Time, String, nil)

    The close time



152
153
154
# File 'lib/schwab/resources/order.rb', line 152

def close_time
  self[:closeTime] || self[:close_time] || self[:filledTime] || self[:filled_time]
end

#closing?Boolean

Check if closing order

Returns:

  • (Boolean)

    True if closing



346
347
348
349
# File 'lib/schwab/resources/order.rb', line 346

def closing?
  inst = instruction&.upcase
  ["BUY_TO_CLOSE", "SELL_TO_CLOSE", "BUY_TO_COVER"].include?(inst)
end

#complete?Boolean

Check if order is complete (filled, cancelled, rejected, or expired)

Returns:

  • (Boolean)

    True if complete



276
277
278
# File 'lib/schwab/resources/order.rb', line 276

def complete?
  filled? || cancelled? || rejected? || expired?
end

#complex?Boolean

Check if this is a complex order (multi-leg)

Returns:

  • (Boolean)

    True if complex order



193
194
195
# File 'lib/schwab/resources/order.rb', line 193

def complex?
  order_legs.size > 1
end

#day_order?Boolean

Check if day order

Returns:

  • (Boolean)

    True if day order



390
391
392
# File 'lib/schwab/resources/order.rb', line 390

def day_order?
  duration&.upcase == "DAY"
end

#durationString Also known as: time_in_force

Get duration (time in force)

Returns:

  • (String)

    The duration (DAY, GTC, FOK, IOC, etc.)



61
62
63
# File 'lib/schwab/resources/order.rb', line 61

def duration
  self[:duration] || self[:timeInForce] || self[:time_in_force]
end

#entered_timeTime, String

Get entered time

Returns:

  • (Time, String)

    The time order was entered



145
146
147
# File 'lib/schwab/resources/order.rb', line 145

def entered_time
  self[:enteredTime] || self[:entered_time] || self[:createdTime] || self[:created_time]
end

#equity_order?Boolean

Check if equity order

Returns:

  • (Boolean)

    True if equity order



363
364
365
366
367
# File 'lib/schwab/resources/order.rb', line 363

def equity_order?
  order_legs.all? do |leg|
    leg[:instrument] && leg[:instrument][:assetType] == "EQUITY"
  end
end

#expired?Boolean

Check if order is expired

Returns:

  • (Boolean)

    True if expired



262
263
264
# File 'lib/schwab/resources/order.rb', line 262

def expired?
  status&.upcase == "EXPIRED"
end

#extended_hours?Boolean

Check if extended hours order

Returns:

  • (Boolean)

    True if extended hours



381
382
383
# File 'lib/schwab/resources/order.rb', line 381

def extended_hours?
  ["AM", "PM", "SEAMLESS"].include?(session&.upcase)
end

#fill_percentageFloat

Calculate fill percentage

Returns:

  • (Float)

    The fill percentage (0-100)



418
419
420
421
422
# File 'lib/schwab/resources/order.rb', line 418

def fill_percentage
  return 0.0 if quantity.zero?

  ((filled_quantity / quantity) * 100).round(2)
end

#filled?Boolean

Check if order is filled

Returns:

  • (Boolean)

    True if filled



233
234
235
# File 'lib/schwab/resources/order.rb', line 233

def filled?
  status&.upcase == "FILLED"
end

#filled_quantityFloat

Get filled quantity

Returns:

  • (Float)

    The filled quantity



103
104
105
# File 'lib/schwab/resources/order.rb', line 103

def filled_quantity
  (self[:filledQuantity] || self[:filled_quantity] || 0).to_f
end

#fok?Boolean

Check if FOK order

Returns:

  • (Boolean)

    True if FOK



404
405
406
# File 'lib/schwab/resources/order.rb', line 404

def fok?
  duration&.upcase == "FOK" || duration&.upcase == "FILL_OR_KILL"
end

#gtc?Boolean

Check if GTC order

Returns:

  • (Boolean)

    True if GTC



397
398
399
# File 'lib/schwab/resources/order.rb', line 397

def gtc?
  duration&.upcase == "GTC" || duration&.upcase == "GOOD_TILL_CANCEL"
end

#has_children?Boolean

Check if order has child orders

Returns:

  • (Boolean)

    True if has child orders



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

def has_children?
  !child_orders.empty?
end

#instructionString

Get instruction (BUY, SELL, etc.)

Returns:

  • (String)

    The instruction



69
70
71
72
73
74
75
# File 'lib/schwab/resources/order.rb', line 69

def instruction
  if order_legs&.first
    order_legs.first[:instruction]
  else
    self[:instruction] || self[:orderInstruction] || self[:order_instruction]
  end
end

#ioc?Boolean

Check if IOC order

Returns:

  • (Boolean)

    True if IOC



411
412
413
# File 'lib/schwab/resources/order.rb', line 411

def ioc?
  duration&.upcase == "IOC" || duration&.upcase == "IMMEDIATE_OR_CANCEL"
end

#limit_order?Boolean

Check if limit order

Returns:

  • (Boolean)

    True if limit order



292
293
294
# File 'lib/schwab/resources/order.rb', line 292

def limit_order?
  order_type&.upcase == "LIMIT"
end

#limit_priceFloat?

Get limit price

Returns:

  • (Float, nil)

    The limit price



124
125
126
# File 'lib/schwab/resources/order.rb', line 124

def limit_price
  self[:limitPrice] || self[:limit_price]
end

#market_order?Boolean

Check if market order

Returns:

  • (Boolean)

    True if market order



285
286
287
# File 'lib/schwab/resources/order.rb', line 285

def market_order?
  order_type&.upcase == "MARKET"
end

#opening?Boolean

Check if opening order

Returns:

  • (Boolean)

    True if opening



338
339
340
341
# File 'lib/schwab/resources/order.rb', line 338

def opening?
  inst = instruction&.upcase
  ["BUY_TO_OPEN", "SELL_TO_OPEN"].include?(inst)
end

#option_order?Boolean

Check if option order

Returns:

  • (Boolean)

    True if option order



354
355
356
357
358
# File 'lib/schwab/resources/order.rb', line 354

def option_order?
  order_legs.any? do |leg|
    leg[:instrument] && leg[:instrument][:assetType] == "OPTION"
  end
end

#order_idString Also known as: id

Get order ID

Returns:

  • (String)

    The order ID



25
26
27
# File 'lib/schwab/resources/order.rb', line 25

def order_id
  self[:orderId] || self[:order_id] || self[:id]
end

#order_legsArray

Get order legs

Returns:

  • (Array)

    Array of order legs



159
160
161
# File 'lib/schwab/resources/order.rb', line 159

def order_legs
  self[:orderLegCollection] || self[:order_leg_collection] || self[:legs] || []
end

#order_typeString

Get order type

Returns:

  • (String)

    The order type (MARKET, LIMIT, STOP, etc.)



47
48
49
# File 'lib/schwab/resources/order.rb', line 47

def order_type
  self[:orderType] || self[:order_type] || self[:type]
end

#partially_filled?Boolean

Check if order is partially filled

Returns:

  • (Boolean)

    True if partially filled



240
241
242
# File 'lib/schwab/resources/order.rb', line 240

def partially_filled?
  filled_quantity > 0 && filled_quantity < quantity
end

#pending?Boolean

Check if order is pending

Returns:

  • (Boolean)

    True if pending



209
210
211
212
213
214
215
216
217
218
219
# File 'lib/schwab/resources/order.rb', line 209

def pending?
  [
    "PENDING_ACTIVATION",
    "PENDING_APPROVAL",
    "PENDING_SUBMISSION",
    "AWAITING_PARENT_ORDER",
    "AWAITING_CONDITION",
    "AWAITING_MANUAL_REVIEW",
    "AWAITING_UR_OUT",
  ].include?(status&.upcase)
end

#priceFloat?

Get price (for limit/stop orders)

Returns:

  • (Float, nil)

    The price



117
118
119
# File 'lib/schwab/resources/order.rb', line 117

def price
  self[:price] || self[:limitPrice] || self[:limit_price] || self[:stopPrice] || self[:stop_price]
end

#quantityFloat

Get quantity

Returns:

  • (Float)

    The quantity



92
93
94
95
96
97
98
# File 'lib/schwab/resources/order.rb', line 92

def quantity
  if order_legs&.first
    order_legs.first[:quantity].to_f
  else
    (self[:quantity] || self[:totalQuantity] || self[:total_quantity] || 0).to_f
  end
end

#regular_hours?Boolean

Check if regular hours order

Returns:

  • (Boolean)

    True if regular hours



374
375
376
# File 'lib/schwab/resources/order.rb', line 374

def regular_hours?
  session&.upcase == "NORMAL"
end

#rejected?Boolean

Check if order is rejected

Returns:

  • (Boolean)

    True if rejected



255
256
257
# File 'lib/schwab/resources/order.rb', line 255

def rejected?
  status&.upcase == "REJECTED"
end

#remaining_quantityFloat

Get remaining quantity

Returns:

  • (Float)

    The remaining quantity



110
111
112
# File 'lib/schwab/resources/order.rb', line 110

def remaining_quantity
  (self[:remainingQuantity] || self[:remaining_quantity] || (quantity - filled_quantity)).to_f
end

#replaced?Boolean

Check if order is replaced

Returns:

  • (Boolean)

    True if replaced



269
270
271
# File 'lib/schwab/resources/order.rb', line 269

def replaced?
  ["REPLACED", "PENDING_REPLACE"].include?(status&.upcase)
end

#replaced_ordersArray<Order>

Get replaced orders

Returns:

  • (Array<Order>)

    Array of replaced orders



183
184
185
186
187
188
# File 'lib/schwab/resources/order.rb', line 183

def replaced_orders
  replaced = self[:replacingOrderCollection] || self[:replacing_order_collection] || []
  replaced.map do |order_data|
    order_data.is_a?(Order) ? order_data : Order.new(order_data, client)
  end
end

#sell?Boolean

Check if sell order

Returns:

  • (Boolean)

    True if sell



330
331
332
333
# File 'lib/schwab/resources/order.rb', line 330

def sell?
  inst = instruction&.upcase
  ["SELL", "SELL_SHORT", "SELL_TO_OPEN", "SELL_TO_CLOSE"].include?(inst)
end

#sessionString

Get session (regular or extended hours)

Returns:

  • (String)

    The session (NORMAL, AM, PM, SEAMLESS)



54
55
56
# File 'lib/schwab/resources/order.rb', line 54

def session
  self[:session] || self[:tradingSession] || self[:trading_session]
end

#single_leg?Boolean

Check if this is a single-leg order

Returns:

  • (Boolean)

    True if single-leg



200
201
202
# File 'lib/schwab/resources/order.rb', line 200

def single_leg?
  order_legs.size == 1
end

#statusString

Get order status

Returns:

  • (String)

    The order status



40
41
42
# File 'lib/schwab/resources/order.rb', line 40

def status
  self[:status] || self[:orderStatus] || self[:order_status]
end

#stop_limit_order?Boolean

Check if stop limit order

Returns:

  • (Boolean)

    True if stop limit order



306
307
308
# File 'lib/schwab/resources/order.rb', line 306

def stop_limit_order?
  order_type&.upcase == "STOP_LIMIT"
end

#stop_order?Boolean

Check if stop order

Returns:

  • (Boolean)

    True if stop order



299
300
301
# File 'lib/schwab/resources/order.rb', line 299

def stop_order?
  order_type&.upcase == "STOP"
end

#stop_priceFloat?

Get stop price

Returns:

  • (Float, nil)

    The stop price



131
132
133
# File 'lib/schwab/resources/order.rb', line 131

def stop_price
  self[:stopPrice] || self[:stop_price]
end

#symbolString?

Get the symbol for single-leg orders

Returns:

  • (String, nil)

    The symbol



80
81
82
83
84
85
86
87
# File 'lib/schwab/resources/order.rb', line 80

def symbol
  if order_legs&.size == 1
    leg = order_legs.first
    leg[:instrument][:symbol] if leg[:instrument]
  elsif self[:symbol]
    self[:symbol]
  end
end

#to_display_stringString

Get formatted display string for the order

Returns:

  • (String)

    Formatted order string



427
428
429
430
431
432
433
434
435
436
437
438
# File 'lib/schwab/resources/order.rb', line 427

def to_display_string
  parts = []
  parts << status
  parts << instruction
  parts << quantity.to_i.to_s
  parts << symbol if symbol
  parts << order_type
  parts << "@#{price}" if price
  parts << "(#{fill_percentage}% filled)" if partially_filled?

  parts.compact.join(" ")
end

#trailing_stop?Boolean

Check if trailing stop order

Returns:

  • (Boolean)

    True if trailing stop



313
314
315
# File 'lib/schwab/resources/order.rb', line 313

def trailing_stop?
  order_type&.upcase&.include?("TRAILING")
end