ib-extensions 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +6 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +9 -0
  7. data/Gemfile.lock +112 -0
  8. data/Guardfile +24 -0
  9. data/README.md +99 -0
  10. data/Rakefile +6 -0
  11. data/bin/console +96 -0
  12. data/bin/console.yml +3 -0
  13. data/bin/gateway.rb +97 -0
  14. data/bin/setup +8 -0
  15. data/changelog.md +31 -0
  16. data/examples/cancel_orders +74 -0
  17. data/examples/eod +35 -0
  18. data/examples/input.rb +475 -0
  19. data/examples/market_price +57 -0
  20. data/examples/option_chain +67 -0
  21. data/examples/place_and_modify_order +162 -0
  22. data/examples/place_bracket_order +62 -0
  23. data/examples/place_butterfly_order +104 -0
  24. data/examples/place_combo_order +70 -0
  25. data/examples/place_limit_order +82 -0
  26. data/examples/place_the_limit_order +145 -0
  27. data/examples/volatility_research +139 -0
  28. data/examples/what_if_order +90 -0
  29. data/ib-extensions.gemspec +37 -0
  30. data/lib/ib-gateway.rb +5 -0
  31. data/lib/ib/alerts/base-alert.rb +128 -0
  32. data/lib/ib/alerts/gateway-alerts.rb +15 -0
  33. data/lib/ib/alerts/order-alerts.rb +68 -0
  34. data/lib/ib/eod.rb +152 -0
  35. data/lib/ib/extensions.rb +9 -0
  36. data/lib/ib/extensions/contract.rb +37 -0
  37. data/lib/ib/extensions/version.rb +5 -0
  38. data/lib/ib/flex.rb +150 -0
  39. data/lib/ib/gateway.rb +425 -0
  40. data/lib/ib/gateway/account-infos.rb +115 -0
  41. data/lib/ib/gateway/order-handling.rb +150 -0
  42. data/lib/ib/market-price.rb +134 -0
  43. data/lib/ib/models/account.rb +329 -0
  44. data/lib/ib/models/spread.rb +159 -0
  45. data/lib/ib/option-chain.rb +198 -0
  46. data/lib/ib/option-greeks.rb +88 -0
  47. data/lib/ib/order-prototypes.rb +110 -0
  48. data/lib/ib/order_prototypes/abstract.rb +67 -0
  49. data/lib/ib/order_prototypes/combo.rb +46 -0
  50. data/lib/ib/order_prototypes/forex.rb +40 -0
  51. data/lib/ib/order_prototypes/limit.rb +177 -0
  52. data/lib/ib/order_prototypes/market.rb +116 -0
  53. data/lib/ib/order_prototypes/pegged.rb +173 -0
  54. data/lib/ib/order_prototypes/premarket.rb +31 -0
  55. data/lib/ib/order_prototypes/stop.rb +202 -0
  56. data/lib/ib/order_prototypes/volatility.rb +39 -0
  57. data/lib/ib/spread-prototypes.rb +62 -0
  58. data/lib/ib/spread_prototypes/butterfly.rb +79 -0
  59. data/lib/ib/spread_prototypes/calendar.rb +85 -0
  60. data/lib/ib/spread_prototypes/stock-spread.rb +48 -0
  61. data/lib/ib/spread_prototypes/straddle.rb +75 -0
  62. data/lib/ib/spread_prototypes/strangle.rb +96 -0
  63. data/lib/ib/spread_prototypes/vertical.rb +84 -0
  64. data/lib/ib/verify.rb +226 -0
  65. metadata +206 -0
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Fetching market-prices for 500 Contracts
4
+ #
5
+ # Ensure to run `ruby input.rb` prior to the first run.
6
+ # That initializes the watchlist `W500`.
7
+ #
8
+ # First a (fast) asynchron request is fired.
9
+ # Second a (much slower) synchron attempt is drawn
10
+
11
+ require 'bundler/setup'
12
+ require 'ib/symbols'
13
+ require 'ib/market-price'
14
+ require 'yaml'
15
+
16
+ # First, connect to IB TWS and subscribe for events.
17
+ ib = IB::Connection.new :client_id => 1112 do | gw | #, :port => 7497 # TWS
18
+
19
+ # Subscribe to TWS alerts/errors
20
+ gw.subscribe(:Alert) { |msg| puts msg.to_human }
21
+ # Set log level
22
+ gw.logger.level = Logger::FATAL # DEBUG -- INFO -- WARN -- ERROR -- FATAL
23
+
24
+ end
25
+ # Put your code here
26
+ # ...
27
+ IB::Symbols.allocate_collection :w500
28
+
29
+ puts
30
+ puts '*'*40
31
+ puts "(1) asynchon fetching of snapshot data "
32
+ start = Time.now;
33
+ IB::Symbols::W500.bunch(45,1){|x| x.map{|y| y.market_price(thread: true)}};
34
+
35
+ print "Finished Time:"
36
+ puts second_duration = Time.now - start
37
+ puts "Prices: "; sleep(7)
38
+ puts IB::Symbols::W500.map{|x| x.misc}.join( ' - ' )
39
+
40
+ IB::Connection.current.disconnect
41
+ IB::Connection.current.connect
42
+ puts '*'*40
43
+ puts "(2) sequencial fetching of snapshot data "
44
+ start = Time.now;
45
+ prices = IB::Symbols::W500.map &:market_price
46
+
47
+ print "Finished Time:"
48
+ puts first_duration = Time.now - start
49
+
50
+ puts "Prices: #{prices.map( &:to_s ).join(" - ")}"
51
+
52
+
53
+ puts
54
+ puts "first_duration: #{first_duration} s "
55
+ puts "second_duration: #{second_duration} s "
56
+
57
+ puts "finished"
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Gets the OptionChain of GE
4
+
5
+ require 'bundler/setup'
6
+ require 'ib-api'
7
+ require 'ib/verify'
8
+
9
+ # First, connect to IB TWS and subscribe for events.
10
+ ib = IB::Connection.new :client_id => 1112 do | gw | #, :port => 7497 # TWS
11
+
12
+ # Subscribe to TWS alerts/errors
13
+ gw.subscribe(:Alert) { |msg| puts msg.to_human }
14
+ # Set log level
15
+ gw.logger.level = Logger::ERROR # DEBUG # -- INFO -- WARN -- ERROR -- FATAL
16
+
17
+ end
18
+
19
+ TheYear = 2021
20
+ TheStrike = 6
21
+ TheRight = :put
22
+
23
+ # get expiries (last-trading-days)
24
+ the_contract = IB::Option.new symbol: 'GE',
25
+ currency: 'USD',
26
+ exchange: 'SMART',
27
+ expiry: TheYear,
28
+ strike: TheStrike,
29
+ right: TheRight
30
+
31
+ provided_expiries = Array.new
32
+
33
+ puts "Using #{the_contract.to_human}"
34
+
35
+ # get all available expiries
36
+ the_contract.verify do | detected_contract |
37
+ # last trading day: format yyyy-mm-dd
38
+ # expiry: format yyyymmdd
39
+ provided_expiries << detected_contract.last_trading_day
40
+ end
41
+ puts "detected Expiries #{provided_expiries.sort{|a,b| a.to_f <=> b.to_f }.join(" -- ")}"
42
+ puts
43
+
44
+
45
+
46
+ # get provided strikes
47
+ option_matrix = provided_expiries.map do | last_trading_day |
48
+ provided_strikes = Array.new
49
+
50
+ # because we used last_trading day as input to the expiry's array, it has to be assigned that way, too
51
+ the_contract = IB::Option.new symbol: 'GE', currency: 'USD', exchange: 'SMART', last_trading_day: last_trading_day, right: TheRight
52
+
53
+ the_contract.verify do | detected_contract |
54
+ provided_strikes << detected_contract.strike
55
+ end
56
+ puts "Expiry: #{the_contract.expiry}"
57
+ puts "Strikes: "+ provided_strikes.join(" -- ")
58
+ provided_strikes # return array
59
+
60
+ end
61
+
62
+ puts "NOTICE: Strikes are not sorted when :RequestContractData is used"
63
+ # print summary
64
+ #option_matrix.zip( provided_expiries) do | strikes, expiry|
65
+ # puts "expiry #{strikes}"
66
+ # puts "provided strikes: #{strikes.join(' ')}"
67
+ #end
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ ## This script places WFC buy order for 100 lots
4
+ #
5
+ ## RUN ONLY ON A DEMO ACCOUNT
6
+
7
+ module OrderPlacement
8
+
9
+ # Utility Method
10
+ #
11
+ # gets the most recent price of the asset
12
+ # User has to specify order in the block provided
13
+ # returns the order_id
14
+ #
15
+ def place_the_order( contract: IB::Symbols::Stocks.wfc, modus: :place ) # modus: place or modify
16
+ # First, get the current connection
17
+ ib = IB::Connection.current
18
+ raise 'Unable to place order, no connection' unless ib && ib.connected?
19
+ # Ask the TWS for the last available price for the asset,
20
+ # Optional: switch to delayed data, if no market-data subscription is booked;
21
+ # Unsubscribe from the Marketdata-Feed after successfully received the data
22
+ ib.send_message :RequestMarketDataType, :market_data_type => :delayed
23
+ the_id = ib.send_message :RequestMarketData, contract: contract
24
+ ib.wait_for :TickPrice
25
+ ib.send_message :CancelMarketData, id: the_id
26
+ # We received High, Low, (perhaps open and close, too), choose the maximum value for reference
27
+ # and clear the received-array for proper bookkeeping
28
+ last_price = ib.received[:TickPrice].price.map(&:to_f).max
29
+ ib.clear_received :TickPrice
30
+ # let the calling method decide how to use the price
31
+ # the calling method should return a valid order
32
+ order = yield(last_price.presence || 47)
33
+ # to finish, we place the order using the given contract and return the order_id
34
+ the_order_id = if modus == :place
35
+ ib.place_order order, contract
36
+ else
37
+ ib.modify_order order, contract
38
+ end
39
+ ib.wait_for :OpenOrder, 3
40
+ the_order_id # return value
41
+ end
42
+ end
43
+
44
+
45
+
46
+
47
+
48
+
49
+ require 'bundler/setup'
50
+ require 'ib-api'
51
+ require 'ib/symbols'
52
+ require 'ib/order-prototypes'
53
+
54
+ include OrderPlacement
55
+
56
+ # Only for Advisor accounts: you need to provide account_code such as DU666777
57
+ account_code = ARGV[0] || ''
58
+ puts "\n" * 3
59
+ puts "*" * 50
60
+ puts " We are going to place a BUY-order on Wells Fargo on the account #{account_code} "
61
+ puts ""
62
+ puts " The Order is placed by the Order-Prototye »Limit.order»"
63
+ puts " "
64
+ puts " The Order is left open after finishing this script. You have to cancel it manualy"
65
+ puts "*" * 50
66
+ puts "\n" * 3
67
+ #
68
+ # First, connect to IB TWS. Arbitrary :client_id is used to identify your script
69
+ ib = IB::Connection.new client_id: 1112 do | gw | #, :port => 7496 # TWS
70
+
71
+ # Subscribe to TWS alerts/errors and order-related messages prior to the connection of the client
72
+ gw.subscribe(:Alert, :ManagedAccounts, :OpenOrder, :OrderStatus, :ContractDataEnd ) { |msg| puts msg.to_human }
73
+ gw.subscribe(:ContractData ) do |msg|
74
+ puts msg.contract.to_human + "\n"
75
+ end
76
+ gw.logger.level = Logger::FATAL # DEBUG -- INFO -- WARN -- ERROR -- FATAL
77
+
78
+ end
79
+
80
+ buy_order = nil # placeholder for buy_order defined in the block
81
+ contract = IB::Symbols::Stocks.wfc
82
+ puts '*'*10 + ' Introduction '+ '*'*10
83
+ puts IB::Limit.summary
84
+ puts "\nSupported Parameter \n -------------------------- "
85
+ puts IB::Limit.parameters
86
+
87
+ buy_order = IB::Limit.order size: 100,
88
+ price: 0, # dummy, specified later
89
+ action: :buy,
90
+ account: account_code
91
+
92
+ the_initial_order_id = place_the_order( contract: contract ) do | asset_price |
93
+ buy_order.limit_price = ( asset_price -( asset_price * 0.1)).round
94
+ puts buy_order.to_human
95
+ buy_order # return_value
96
+ end
97
+
98
+
99
+ puts "going to modify the order "
100
+
101
+ puts "\n******** Press <Enter> to proceed... *********\n\n"
102
+ STDIN.gets
103
+
104
+ puts "changing price by 1$"
105
+
106
+ the_modified_order_id = place_the_order( contract: contract, modus: :modify ) do | asset_price |
107
+ buy_order.limit_price = ( asset_price - 1 - ( asset_price * 0.1)).round
108
+ puts buy_order.to_human
109
+ buy_order # return_value
110
+ end
111
+
112
+
113
+ ib.send_message :RequestAllOpenOrders
114
+
115
+
116
+ puts "\n******** Press <Enter> to cancel... *********\n\n"
117
+ STDIN.gets
118
+
119
+
120
+ ## RUN ONLY ON A DEMO ACCOUNT
121
+ #
122
+ #
123
+ # expected output
124
+ #
125
+ #12:13:05.096 Got message 15 (IB::Messages::Incoming::ManagedAccounts)
126
+ #12:13:05.097 No subscribers for message IB::Messages::Incoming::ManagedAccounts!
127
+ #12:13:05.137 Got message 9 (IB::Messages::Incoming::NextValidId)
128
+ #12:13:05.137 Got next valid order id: 1.
129
+ #------sendto ---------(debugging output in outgoing/abstract_message)
130
+ #["'9", "8", "56", "", "WFC", "STK", "", "0.0", "", "", "NYSE", "", "USD", "", "", "0", "", "", "\""]
131
+ #------sendto ---------
132
+ # A Limit order is an order to buy or sell at a specified price or better.
133
+ # The Limit order ensures that if the order fills, it will not fill at a price less favorable than
134
+ # your limit price, but it does not guarantee a fill.
135
+ # It appears in the orderbook.
136
+ #Supported Parameter
137
+ # --------------------------
138
+ #Required : action --> {"B"=>:buy, "S"=>:sell, "T"=>:short, "X"=>:short_exempt}
139
+ # : total_quantity --> also aliased as :size
140
+ # : limit_price --> decimal
141
+ # ---------------
142
+ #Optional : account --> Account(number) to trade on
143
+ # ---------------
144
+ #<Order: LMT GTC buy 100 1.13 New #/ from /DU167348>
145
+ #------sendto ---------(debugging output in outgoing/abstract_message)
146
+ #["\\xB03", "45", "1", "", "WFC", "STK", "", "0.0", "", "", "NYSE", "", "USD", "", "", "", "", "BUY", "100", "LMT", "1.13", "", "GTC", "", "DU167348", "O", "0", "", "1", "0", "0", "0", "0", "0", "0", "0", "", "0", "", "", "", "", "", "", "", "0", "", "-1", "0", "", "", "0", "", "", "1", "1", "", "0", "", "", "", "", "", "0", "", "", "", "", "0", "", "", "", "", "", "", "", "", "", "", "0", "", "", "0", "0", "", "", "0", "", "0", "0", "0", "0", "", "", "", "", "", "", "", "", "", "", "", "\""]
147
+ #------sendto ---------
148
+ #12:13:05.290 Got message 10 (IB::Messages::Incoming::ContractData)
149
+ #<Stock: WFC USD>
150
+ #12:13:05.291 Got message 52 (IB::Messages::Incoming::ContractDataEnd)
151
+ #<ContractDataEnd: request_id 56 >
152
+ #
153
+ #******** Press <Enter> to cancel... *********
154
+ #
155
+ #12:13:05.303 Got message 3 (IB::Messages::Incoming::OrderStatus)
156
+ #<OrderStatus: <OrderState: ApiPending #1/0 from 1112 filled 0.0/100.0 at 0.0/0.0>>
157
+ #12:13:05.304 Got message 53 (IB::Messages::Incoming::OpenOrderEnd)
158
+ #12:13:05.304 No subscribers for message IB::Messages::Incoming::OpenOrderEnd!
159
+ #12:13:05.712 Got message 5 (IB::Messages::Incoming::OpenOrder)
160
+ #<OpenOrder: <Stock: WFC USD> <Order: LMT GTC buy 100.0 1.13 Submitted #1/1562725191 from 1112/DU167348 fee 0.0>>
161
+ #12:13:05.714 Got message 3 (IB::Messages::Incoming::OrderStatus)
162
+ #<OrderStatus: <OrderState: Submitted #1/1562725191 from 1112 filled 0.0/100.0 at 0.0/0.0 why_held >>
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This script places WFC bracketed buy order.
4
+ # Two child orders are attached:
5
+ # STOP order
6
+ # LIMIT order (profit target)
7
+
8
+ require 'rubygems'
9
+ require 'bundler/setup'
10
+ require 'ib-api'
11
+ require 'ib/symbols'
12
+ require 'ib/order-prototypes'
13
+ # Only for Advisor accounts: you need to provide account_code such as U666777
14
+ account_code = ARGV[0] || ''
15
+ # First, connect to IB TWS. Arbitrary :client_id is used to identify your script
16
+ ib = IB::Connection.new :client_id => 1112 do | gw | #, :port => 7497 # TWS
17
+
18
+ # Subscribe to TWS alerts/errors and order-related messages
19
+ gw.subscribe(:Alert, :OpenOrder, :OrderStatus, :ManagedAccounts) { |msg| puts msg.to_human }
20
+ end
21
+
22
+ symbol = IB::Symbols::Stocks[:wfc]
23
+
24
+ order_price = 24
25
+ stop_price = order_price - 0.25
26
+ profit_price = order_price + 0.25
27
+
28
+ #-- Parent Order --
29
+ buy_order = IB::Limit.order :total_quantity => 100,
30
+ :price => order_price,
31
+ :action => :buy,
32
+ :algo_strategy => '',
33
+ :transmit => false,
34
+ account: account_code
35
+ ib.wait_for :NextValidId
36
+
37
+ #-- Child STOP --
38
+ stop_order = IB::SimpleStop.order :total_quantity => 100,
39
+ :price => stop_price,
40
+ :action => :sell,
41
+ :parent_id => buy_order.local_id,
42
+ account: account_code
43
+ #-- Profit LMT
44
+ profit_order = IB::Limit.order :total_quantity => 100,
45
+ :price => profit_price,
46
+ :action => :sell,
47
+ :parent_id => buy_order.local_id,
48
+ account: account_code
49
+
50
+ # place parent order
51
+ ib.place_order buy_order, symbol
52
+ stop_order.parent_id = buy_order.local_id
53
+ profit_order.parent_id = buy_order.local_id
54
+
55
+ # place child orders
56
+ ib.place_order stop_order, symbol
57
+ ib.place_order profit_order, symbol
58
+
59
+ ib.send_message :RequestAllOpenOrders
60
+
61
+ puts "\n******** Press <Enter> to cancel... *********\n\n"
62
+ STDIN.gets
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This script places GOOG option butterfly combo order
4
+
5
+ require 'rubygems'
6
+ require 'bundler/setup'
7
+ require 'ib-api'
8
+ require 'ib/verify'
9
+ require 'ib/market-price'
10
+ require 'ib/order-prototypes'
11
+
12
+ # Utility method that helps us build multi-legged (BAG) Orders
13
+ def butterfly symbol, expiry, right, *strikes
14
+
15
+ legs = strikes.zip([1, -2, 1]).map do |strike, weight|
16
+ # Create contract
17
+ the_leg = nil
18
+ IB::Option.new( :symbol => symbol,
19
+ :expiry => expiry,
20
+ :right => right,
21
+ :strike => strike).verify do | c |
22
+
23
+ # Create Comboleg from con_id and weight
24
+ the_leg = IB::ComboLeg.new :con_id => c.con_id, :weight => weight
25
+ end
26
+ the_leg # return_value
27
+ end
28
+ if legs.size < 3
29
+ puts "Could'nd initialize all legs"
30
+ nil # return nil
31
+ else
32
+ # Create and return new Combo contract
33
+ IB::Bag.new :symbol => symbol,
34
+ :currency => "USD", # Only US options in combo Contracts
35
+ :exchange => "SMART",
36
+ :combo_legs => legs
37
+ end
38
+ end
39
+
40
+ # Only for Advisor accounts: you need to provide account_code such as U666777
41
+ account_code = ARGV[0] || ''
42
+
43
+ #
44
+ # First, connect to IB TWS. Arbitrary :client_id is used to identify your script
45
+ ib = IB::Connection.new :client_id => 1112 do | gw | #, :port => 7497 # TWS
46
+
47
+ # Subscribe to TWS alerts/errors and order-related messages
48
+ gw.subscribe(:Alert, :OpenOrder, :OrderStatus, :ManagedAccounts) { |msg| puts msg.to_human }
49
+ end
50
+ ib.wait_for :NextValidId
51
+
52
+ # Create multi-legged option Combo using utility method above
53
+ combo = butterfly 'WMT', '20201218', 'CALL', 145, 150 , 155
54
+ unless combo.nil?
55
+ puts "MARKETPRICE: #{combo.market_price}"
56
+ # Create Order stub
57
+ order = IB::Limit.order total_quantity: 10, # 10 butterflies
58
+ limit_price: 0.06, # at 0.06 x 100 USD per contract
59
+ action: :buy,
60
+ account: account_code
61
+
62
+
63
+ ib.place_order order, combo
64
+
65
+ ib.wait_for [:OpenOrder, 3], [:OrderStatus, 2]
66
+
67
+ puts "\n******** Press <Enter> to cancel... *********\n\n"
68
+ STDIN.gets
69
+ end
70
+
71
+ ### Expected output
72
+
73
+ #./place_butterfly_order DU167349
74
+ #Connected to server, version: 137,
75
+ # connection time: 2020-09-03 05:13:24 +0000 local, 2020-09-03T05:13:24+00:00 remote.
76
+ #< ManagedAccounts: DF167347 - DU167348 - DU167349>
77
+ #Got next valid order id: 65.
78
+ #TWS Warning 2104: Market data farm connection is OK:eufarm
79
+ #TWS Warning 2104: Market data farm connection is OK:usopt
80
+ #TWS Warning 2104: Market data farm connection is OK:usfarm
81
+ #TWS Warning 2107: HMDS data farm connection is inactive but should be available upon demand.euhmds
82
+ #TWS Error 354: Requested market data is not subscribed.
83
+ #MARKETPRICE: []
84
+ #<OpenOrder: <Bag: WMT SMART USD legs: 418440165|1,418440170|-2,418440175|1 > <Order: LMT GTC buy 10.0 @ 0.06 PreSubmitted #65/1750019075 from 1112/DU167349>>
85
+ #<OrderState: PreSubmitted #65/1750019075 from 1112 filled 0.0/10.0 at 0.0/0.0 why_held locate>
86
+ #
87
+ #******** Press <Enter> to cancel... *********
88
+ #
89
+ #<OpenOrder: <Bag: WMT SMART USD legs: 418440165|1,418440170|-2,418440175|1 > <Order: LMT GTC buy 10.0 @ 0.06 Submitted #65/1750019075 from 1112/DU167349>>
90
+ #<OrderState: Submitted #65/1750019075 from 1112 filled 0.0/10.0 at 0.0/0.0 why_held >
91
+ #
92
+ #./cancel_orders
93
+ #< ManagedAccounts: DF167347 - DU167348 - DU167349>
94
+ #TWS Warning 2104: Market data farm connection is OK:eufarm
95
+ #TWS Warning 2104: Market data farm connection is OK:usopt
96
+ #TWS Warning 2104: Market data farm connection is OK:usfarm
97
+ #TWS Warning 2107: HMDS data farm connection is inactive but should be available upon demand.euhmds
98
+ #-------------------------------------------------------
99
+ #Remaining Orders
100
+ #-------------------------------------------------------
101
+ #<OpenOrder: <Bag: WMT SMART USD legs: 418440165|1,418440170|-2,418440175|1 > <Order: LMT GTC buy 10.0 @ 0.06 PendingCancel #65/1750019075 from 1112/DU167349>>
102
+ #<OrderState: PendingCancel #65/1750019075 from 1112 filled 0.0/10.0 at 0.0/0.0 why_held >
103
+ #<OpenOrderEnd: >
104
+ ##