stockfighter 0.1.4 → 0.2.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 +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
|