stockfighter 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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: