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 +4 -4
- data/README.md +34 -6
- data/lib/stockfighter/api.rb +0 -23
- data/lib/stockfighter/gm.rb +3 -3
- data/lib/stockfighter/version.rb +1 -1
- data/lib/stockfighter/websockets.rb +102 -0
- data/lib/stockfighter.rb +1 -0
- data/stockfighter.gemspec +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 885259cfcbbb561e9bfcc16d21394302b6615f82
|
4
|
+
data.tar.gz: c1e9ebf5573a7056adcd8a154562b0fa0d76d015
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
|
data/lib/stockfighter/api.rb
CHANGED
@@ -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
|
data/lib/stockfighter/gm.rb
CHANGED
@@ -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
|
-
@
|
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
|
-
@
|
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
|
-
@
|
44
|
+
@state_change_callbacks << block
|
45
45
|
end
|
46
46
|
|
47
47
|
def config
|
data/lib/stockfighter/version.rb
CHANGED
@@ -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
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.
|
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-
|
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:
|