stockfighter 0.2.0 → 0.3.0

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
  SHA1:
3
- metadata.gz: 154ddcc262a23ff8b0405fc5e0ba6d786acbbfd3
4
- data.tar.gz: 269848186df9487af20330d68c6c2a44c0fbcb05
3
+ metadata.gz: 885259cfcbbb561e9bfcc16d21394302b6615f82
4
+ data.tar.gz: c1e9ebf5573a7056adcd8a154562b0fa0d76d015
5
5
  SHA512:
6
- metadata.gz: c013b1a77db9436e7a2d8524a3f92ee8fd10871d8af16e7128511958b6b1cce27a08cc64397a3e15adbadc8d6571cbcca6720c9a9d8047db0226fd39c9d16915
7
- data.tar.gz: 2d6540bfd7b0e1c4d144745772326249e44e94c559df1ddee27c7c070f2e75b009f6ad06b2b3fb94dcb440605dc5869df51f20259fd88db091324302cb279582
6
+ metadata.gz: 0093757ab0fd12e8ae655809826e5424f943be049bd9bb146bd35373b6a94cf64e60d8e8ea0059c09a250acefa77f60e1501f05a23c756019ef31613dc705178
7
+ data.tar.gz: a79a9cb440da8136034f8f6d19787329def1c2fbbbe9aaf002e22efcdf9d320a90bfa3f771399d8ad3bd6fa6830faa2ec8060c9ea8d989cb454e2e42147474bd
data/README.md CHANGED
@@ -18,17 +18,35 @@ Or install it yourself as:
18
18
 
19
19
  $ gem install stockfighter
20
20
 
21
+ ## Features
22
+
23
+ This gem can be used as a simple API client for the trading API, but also
24
+ includes more advanced features for interacting with the (officially undocumented)
25
+ GM API. This includes the ability to start / stop / restart / resume levels,
26
+ automatically fetch level info such as ticker, venue, and account, and also poll
27
+ the GM server regularly and return level and game information.
28
+
29
+ Support for the websockets API is also available
30
+
21
31
  ## Usage
22
32
 
33
+ Coming soon: comprehensive overview and API overview! For now, take a look at
34
+ some of the sample code below.
35
+
23
36
  ### Example
24
37
  ```ruby
25
38
  require 'stockfighter'
26
39
 
27
- # Use the GM to fetch the info automatically
40
+ # Use the GM to fetch level info for the trading API automatically
41
+
42
+ gm = Stockfighter::GM.new(key: "supersecretapikey1234567", level: "first_steps")
43
+
44
+ api = Stockfighter::Api.new(gm.config)
45
+
46
+ # Use the GM to register message callbacks for messages received from the GM. The GM needs to be initialized with polling: true to set up polling of the GM and enable callbacks.
28
47
 
29
- gm = Stockfighter::GM.new(key: "supersecretapikey1234567", level: "first_steps", polling:true)
48
+ gm = Stockfighter::GM.new(key: "supersecretapikey1234567", level: "first_steps", polling: true)
30
49
 
31
- # Register message callbacks - GM needs to be constructed with polling:true for these callbacks to work
32
50
  gm.add_message_callback('success') { |message|
33
51
  puts "\e[#32m#{message}\e[0m"
34
52
  }
@@ -41,8 +59,6 @@ gm.add_state_change_callback { |previous_state, new_state|
41
59
  end
42
60
  }
43
61
 
44
- api = Stockfighter::Api.new(gm.config)
45
-
46
62
  # Restart the level
47
63
 
48
64
  gm.restart
@@ -99,12 +115,24 @@ api = Stockfighter::Api.new(key: key, account: account, symbol: symbol, venue: v
99
115
 
100
116
  ```
101
117
 
118
+ # Websockets api example
119
+
120
+ websockets = Stockfighter::Websockets.new(gm.config)
121
+ websockets.add_quote_callback { |quote|
122
+ puts quote
123
+ }
124
+ websockets.add_execution_callback { |execution|
125
+ puts execution
126
+ }
127
+ websockets.start()
128
+
129
+
102
130
  ## Todo
103
131
 
104
132
  * ~~TODO: Usage instructions!~~
105
133
  * ~~TODO: Game master integration~~
106
134
  * TODO: Tests
107
- * TODO: Error Handling
135
+ * TODO: Error Handling (partially complete)
108
136
 
109
137
  ## Contributing
110
138
 
@@ -15,18 +15,6 @@ module Stockfighter
15
15
  HTTParty.get("#{BASE_URL}/venues/#{@venue}/stocks/#{@symbol}/quote", {"X-Starfighter-Authorization" => @api_key}).parsed_response
16
16
  end
17
17
 
18
- def block_until_first_trade()
19
- puts "Waiting until first trade of #{@symbol}.#{@venue}"
20
-
21
- quote = nil
22
- loop do
23
- quote = get_quote
24
- puts quote
25
- break if quote['last'] != nil
26
- end
27
- quote
28
- end
29
-
30
18
  def place_order(price:, quantity:, direction:, order_type:)
31
19
  order = {
32
20
  "account" => @account,
@@ -42,17 +30,6 @@ module Stockfighter
42
30
  headers: {"X-Starfighter-Authorization" => @api_key}).parsed_response
43
31
  end
44
32
 
45
- def block_until_order_filled(order_id)
46
- puts "Blocking until order #{order_id} is filled"
47
-
48
- loop do
49
- quote = get_quote
50
- order_status = order_status(order_id)
51
- puts "Order Status: #{order_status['direction']} #{order_status['originalQty']} #{order_status['symbol']}.#{order_status['venue']} @ #{order_status['price']} FilledQuantity:#{order_status['totalFilled']} Last Price: #{quote['last']}"
52
- break if not order_status["open"]
53
- end
54
- end
55
-
56
33
  def cancel_order(order_id)
57
34
  HTTParty.delete("#{BASE_URL}/venues/#{@venue}/stocks/#{@symbol}/orders/#{order_id}", headers: {"X-Starfighter-Authorization" => @api_key})
58
35
  end
@@ -13,7 +13,7 @@ module Stockfighter
13
13
 
14
14
  @callback_types = ['success', 'info']
15
15
  @message_callbacks = Hash.new { |h,k| h[k] = [] }
16
- @state_change_callback = []
16
+ @state_change_callbacks = []
17
17
 
18
18
  new_level_response = perform_request("post", "#{GM_URL}/levels/#{level}")
19
19
  previous_state = new_level_response['state']
@@ -26,7 +26,7 @@ module Stockfighter
26
26
 
27
27
  current_state = response['state']
28
28
  if previous_state != current_state
29
- @state_change_callback.each { |callback|
29
+ @state_change_callbacks.each { |callback|
30
30
  callback.call(previous_state, current_state)
31
31
  }
32
32
  previous_state = current_state
@@ -41,7 +41,7 @@ module Stockfighter
41
41
  end
42
42
 
43
43
  def add_state_change_callback(&block)
44
- @state_change_callback << block
44
+ @state_change_callbacks << block
45
45
  end
46
46
 
47
47
  def config
@@ -1,3 +1,3 @@
1
1
  module Stockfighter
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -0,0 +1,102 @@
1
+ require 'httparty'
2
+ require 'websocket-eventmachine-client'
3
+
4
+ module Stockfighter
5
+ class Websockets
6
+
7
+ WS_URL = "https://www.stockfighter.io/ob/api/ws"
8
+
9
+ def initialize(key:, account:, symbol:, venue:)
10
+ @account = account
11
+ @venue = venue
12
+ @quote_callbacks = []
13
+ @execution_callbacks = []
14
+ end
15
+
16
+ def start()
17
+
18
+ EM.epoll
19
+ EM.run do
20
+
21
+ EM.error_handler{ |e|
22
+ abort("Error raised during event loop: #{e}")
23
+ }
24
+
25
+ tickertape = WebSocket::EventMachine::Client.connect(:uri => "#{WS_URL}/#{@account}/venues/#{@venue}/tickertape", :ssl => true)
26
+ tickertape.onopen do
27
+ puts "tickertape websocket: connected"
28
+ end
29
+
30
+ tickertape.onmessage do |msg|
31
+ incoming = JSON.parse(msg)
32
+ if not incoming["ok"]
33
+ raise "tickertape websocket: Error response received: #{msg}"
34
+ end
35
+ if incoming.key?('quote')
36
+ quote = incoming['quote']
37
+ @quote_callbacks.each { |callback|
38
+ callback.call(quote)
39
+ }
40
+ else
41
+ raise "tickertape websocket: TODO: Unhandled message type: #{msg}"
42
+ end
43
+ end
44
+
45
+ tickertape.onerror do |e|
46
+ puts "tickertape websocket: Error #{e}"
47
+ end
48
+
49
+ tickertape.onping do |msg|
50
+ puts "tickertape websocket: Received ping: #{msg}"
51
+ end
52
+
53
+ tickertape.onpong do |msg|
54
+ puts "tickertape websocket: Received pong: #{msg}"
55
+ end
56
+
57
+ tickertape.onclose do
58
+ raise "tickertape websocket: Disconnected"
59
+ end
60
+
61
+ executions = WebSocket::EventMachine::Client.connect(:uri => "#{WS_URL}/#{@account}/venues/#{@venue}/executions", :ssl => true)
62
+ executions.onopen do
63
+ puts "executions websocket: Connected"
64
+ end
65
+
66
+ executions.onmessage do |msg|
67
+ execution = JSON.parse(msg)
68
+ if not execution["ok"]
69
+ raise "execution websocket: Error response received: #{msg}"
70
+ end
71
+ @execution_callbacks.each { |callback|
72
+ callback.call(execution)
73
+ }
74
+ end
75
+
76
+ executions.onerror do |e|
77
+ puts "executions websocket: Error: #{e}"
78
+ end
79
+
80
+ executions.onping do |msg|
81
+ puts "executions websocket: Received ping: #{msg}"
82
+ end
83
+
84
+ executions.onpong do |msg|
85
+ puts "executions websocket: Received pong: #{msg}"
86
+ end
87
+
88
+ executions.onclose do
89
+ raise "executions websocket: Disconnected"
90
+ end
91
+ end
92
+ end
93
+
94
+ def add_quote_callback(&block)
95
+ @quote_callbacks << block
96
+ end
97
+
98
+ def add_execution_callback(&block)
99
+ @execution_callbacks << block
100
+ end
101
+ end
102
+ end
data/lib/stockfighter.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  require "stockfighter/version"
2
2
  require "stockfighter/api"
3
3
  require "stockfighter/gm"
4
+ require "stockfighter/websockets"
data/stockfighter.gemspec CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_runtime_dependency "httparty", "~> 0.13.7"
22
22
  spec.add_runtime_dependency "rufus-scheduler", "~> 3.1.10"
23
+ spec.add_runtime_dependency "websocket-eventmachine-client", "~> 1.1.0"
23
24
  spec.add_development_dependency "bundler", "~> 1.7"
24
25
  spec.add_development_dependency "rake", "~> 10.0"
25
26
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stockfighter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert J Samson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-18 00:00:00.000000000 Z
11
+ date: 2015-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 3.1.10
41
+ - !ruby/object:Gem::Dependency
42
+ name: websocket-eventmachine-client
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.1.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.1.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -82,6 +96,7 @@ files:
82
96
  - lib/stockfighter/api.rb
83
97
  - lib/stockfighter/gm.rb
84
98
  - lib/stockfighter/version.rb
99
+ - lib/stockfighter/websockets.rb
85
100
  - stockfighter.gemspec
86
101
  homepage: https://github.com/rjsamson/stockfighter
87
102
  licenses: