stockfighter 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -1
- data/lib/stockfighter/api.rb +23 -0
- data/lib/stockfighter/gm.rb +81 -30
- data/lib/stockfighter/version.rb +1 -1
- data/stockfighter.gemspec +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 154ddcc262a23ff8b0405fc5e0ba6d786acbbfd3
|
4
|
+
data.tar.gz: 269848186df9487af20330d68c6c2a44c0fbcb05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c013b1a77db9436e7a2d8524a3f92ee8fd10871d8af16e7128511958b6b1cce27a08cc64397a3e15adbadc8d6571cbcca6720c9a9d8047db0226fd39c9d16915
|
7
|
+
data.tar.gz: 2d6540bfd7b0e1c4d144745772326249e44e94c559df1ddee27c7c070f2e75b009f6ad06b2b3fb94dcb440605dc5869df51f20259fd88db091324302cb279582
|
data/README.md
CHANGED
@@ -26,7 +26,20 @@ require 'stockfighter'
|
|
26
26
|
|
27
27
|
# Use the GM to fetch the info automatically
|
28
28
|
|
29
|
-
gm = Stockfighter::GM.new(key: "supersecretapikey1234567", level: "first_steps")
|
29
|
+
gm = Stockfighter::GM.new(key: "supersecretapikey1234567", level: "first_steps", polling:true)
|
30
|
+
|
31
|
+
# Register message callbacks - GM needs to be constructed with polling:true for these callbacks to work
|
32
|
+
gm.add_message_callback('success') { |message|
|
33
|
+
puts "\e[#32m#{message}\e[0m"
|
34
|
+
}
|
35
|
+
gm.add_message_callback('info') { |message|
|
36
|
+
puts "\e[#34m#{message}\e[0m"
|
37
|
+
}
|
38
|
+
gm.add_state_change_callback { |previous_state, new_state|
|
39
|
+
if new_state == 'won'
|
40
|
+
puts "You've won!"
|
41
|
+
end
|
42
|
+
}
|
30
43
|
|
31
44
|
api = Stockfighter::Api.new(gm.config)
|
32
45
|
|
data/lib/stockfighter/api.rb
CHANGED
@@ -15,6 +15,18 @@ 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
|
+
|
18
30
|
def place_order(price:, quantity:, direction:, order_type:)
|
19
31
|
order = {
|
20
32
|
"account" => @account,
|
@@ -30,6 +42,17 @@ module Stockfighter
|
|
30
42
|
headers: {"X-Starfighter-Authorization" => @api_key}).parsed_response
|
31
43
|
end
|
32
44
|
|
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
|
+
|
33
56
|
def cancel_order(order_id)
|
34
57
|
HTTParty.delete("#{BASE_URL}/venues/#{@venue}/stocks/#{@symbol}/orders/#{order_id}", headers: {"X-Starfighter-Authorization" => @api_key})
|
35
58
|
end
|
data/lib/stockfighter/gm.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'httparty'
|
2
|
+
require 'rufus-scheduler'
|
2
3
|
|
3
4
|
module Stockfighter
|
4
5
|
class GM
|
@@ -6,13 +7,41 @@ module Stockfighter
|
|
6
7
|
|
7
8
|
attr_accessor :instance_id
|
8
9
|
|
9
|
-
def initialize(key:, level:)
|
10
|
+
def initialize(key:, level:, polling:false)
|
10
11
|
@api_key = key
|
11
12
|
@level = level
|
12
13
|
|
13
|
-
|
14
|
+
@callback_types = ['success', 'info']
|
15
|
+
@message_callbacks = Hash.new { |h,k| h[k] = [] }
|
16
|
+
@state_change_callback = []
|
14
17
|
|
15
|
-
|
18
|
+
new_level_response = perform_request("post", "#{GM_URL}/levels/#{level}")
|
19
|
+
previous_state = new_level_response['state']
|
20
|
+
|
21
|
+
if polling
|
22
|
+
# websocket API functionality instead of polling would be great here
|
23
|
+
scheduler = Rufus::Scheduler.new(:overlap => false)
|
24
|
+
scheduler.every '10s' do
|
25
|
+
response = get_instance()
|
26
|
+
|
27
|
+
current_state = response['state']
|
28
|
+
if previous_state != current_state
|
29
|
+
@state_change_callback.each { |callback|
|
30
|
+
callback.call(previous_state, current_state)
|
31
|
+
}
|
32
|
+
previous_state = current_state
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_message_callback(type, &block)
|
39
|
+
raise "Unknown message callback type #{type}" unless @callback_types.include? type
|
40
|
+
@message_callbacks[type] << block
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_state_change_callback(&block)
|
44
|
+
@state_change_callback << block
|
16
45
|
end
|
17
46
|
|
18
47
|
def config
|
@@ -24,49 +53,71 @@ module Stockfighter
|
|
24
53
|
end
|
25
54
|
|
26
55
|
def restart
|
27
|
-
|
28
|
-
resp = HTTParty.post("#{GM_URL}/instances/#{@instance_id}/restart", :headers => {"X-Starfighter-Authorization" => @api_key})
|
29
|
-
update_config(resp)
|
30
|
-
end
|
56
|
+
perform_request("post", "#{GM_URL}/instances/#{@instance_id}/restart")
|
31
57
|
end
|
32
58
|
|
33
59
|
def stop
|
34
|
-
|
35
|
-
resp = HTTParty.post("#{GM_URL}/instances/#{@instance_id}/stop", :headers => {"X-Starfighter-Authorization" => @api_key})
|
36
|
-
update_config(resp)
|
37
|
-
end
|
60
|
+
perform_request("post", "#{GM_URL}/instances/#{@instance_id}/stop")
|
38
61
|
end
|
39
62
|
|
40
63
|
def resume
|
41
|
-
|
42
|
-
resp = HTTParty.post("#{GM_URL}/instances/#{@instance_id}/resume", :headers => {"X-Starfighter-Authorization" => @api_key})
|
43
|
-
update_config(resp)
|
44
|
-
end
|
64
|
+
perform_request("post", "#{GM_URL}/instances/#{@instance_id}/resume")
|
45
65
|
end
|
46
66
|
|
47
67
|
def active?
|
48
|
-
response =
|
49
|
-
response["done"]
|
68
|
+
response = get_instance()
|
69
|
+
response["done"]
|
50
70
|
end
|
51
71
|
|
52
|
-
def
|
72
|
+
def get_instance
|
73
|
+
perform_request("get", "#{GM_URL}/instances/#{@instance_id}")
|
74
|
+
end
|
53
75
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
76
|
+
def perform_request(action, url)
|
77
|
+
response = HTTParty.method(action).call(url, :headers => {"X-Starfighter-Authorization" => @api_key})
|
78
|
+
if response.code != 200
|
79
|
+
raise "HTTP error response received from #{url}: #{response.code}"
|
80
|
+
end
|
81
|
+
if not response["ok"]
|
82
|
+
raise "Error response received from #{url}: #{response['error']}"
|
83
|
+
end
|
61
84
|
|
62
|
-
|
85
|
+
if response.key?('flash')
|
86
|
+
flash = response['flash']
|
87
|
+
if flash.key?('success')
|
88
|
+
@message_callbacks['success'].each { |callback|
|
89
|
+
callback.call(flash['success'])
|
90
|
+
}
|
91
|
+
elsif flash.key?('info')
|
92
|
+
@message_callbacks['info'].each { |callback|
|
93
|
+
callback.call(flash['info'])
|
94
|
+
}
|
63
95
|
else
|
64
|
-
raise "
|
96
|
+
raise "TODO: Unhandled flash scenario: #{response}"
|
65
97
|
end
|
66
|
-
else
|
67
|
-
raise "HTTP error response received from #{GM_URL}: #{resp.code}"
|
68
98
|
end
|
99
|
+
|
100
|
+
if response.key?('instructions')
|
101
|
+
if response['instructions'].key?('Instructions')
|
102
|
+
puts "\e[#34m#{response['instructions']['Instructions']}\e[0m"
|
103
|
+
else
|
104
|
+
raise "TODO: Unhandled instructions scenario: #{response}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
if action == 'post'
|
109
|
+
@config = {}
|
110
|
+
@config[:key] = @api_key
|
111
|
+
@config[:account] = response["account"]
|
112
|
+
@config[:venue] = response["venues"][0]
|
113
|
+
@config[:symbol] = response["tickers"][0]
|
114
|
+
|
115
|
+
@instance_id = response["instanceId"]
|
116
|
+
end
|
117
|
+
|
118
|
+
response
|
69
119
|
end
|
70
|
-
|
120
|
+
|
121
|
+
private :perform_request
|
71
122
|
end
|
72
123
|
end
|
data/lib/stockfighter/version.rb
CHANGED
data/stockfighter.gemspec
CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_runtime_dependency "httparty", "~> 0.13.7"
|
22
|
+
spec.add_runtime_dependency "rufus-scheduler", "~> 3.1.10"
|
22
23
|
spec.add_development_dependency "bundler", "~> 1.7"
|
23
24
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
25
|
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.2.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-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.13.7
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rufus-scheduler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.1.10
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.1.10
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|