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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9303ecd757e438d43ccd60406c9f9dd435754db7
4
- data.tar.gz: c5c827c6ae4651d831aa01a18849acebb9956610
3
+ metadata.gz: 154ddcc262a23ff8b0405fc5e0ba6d786acbbfd3
4
+ data.tar.gz: 269848186df9487af20330d68c6c2a44c0fbcb05
5
5
  SHA512:
6
- metadata.gz: 8d44a34db3496aa5b8958e4471eb0f4bb3cd7276fc513b95028e9b6e1dbfa175b22f3efa6f95505a1832afbea3965029f6f0eff00e573eb996ee3eaedc8c76b9
7
- data.tar.gz: ba974cc66552de0c09ffb6f49bd8d275a72e56635189ef6f2a9d6b471dacc440147e5ec4dd484b66a97f2a6d5eb649db9d82a5fe3e731768e5fb4bfbc07c2369
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
 
@@ -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
@@ -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
- resp = HTTParty.post("#{GM_URL}/levels/#{level}", :headers => {"X-Starfighter-Authorization" => @api_key})
14
+ @callback_types = ['success', 'info']
15
+ @message_callbacks = Hash.new { |h,k| h[k] = [] }
16
+ @state_change_callback = []
14
17
 
15
- update_config(resp)
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
- if @instance_id
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
- if @instance_id
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
- if @instance_id
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 = HTTParty.get("#{GM_URL}/instances/#{@instance_id}", :headers => {"X-Starfighter-Authorization" => @api_key})
49
- response["done"] && response["ok"]
68
+ response = get_instance()
69
+ response["done"]
50
70
  end
51
71
 
52
- def update_config(resp)
72
+ def get_instance
73
+ perform_request("get", "#{GM_URL}/instances/#{@instance_id}")
74
+ end
53
75
 
54
- if resp.code == 200
55
- if resp["ok"]
56
- @config = {}
57
- @config[:key] = @api_key
58
- @config[:account] = resp["account"]
59
- @config[:venue] = resp["venues"][0]
60
- @config[:symbol] = resp["tickers"][0]
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
- @instance_id = resp["instanceId"]
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 "Error response received from #{GM_URL}: #{resp['error']}"
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
- private :update_config
120
+
121
+ private :perform_request
71
122
  end
72
123
  end
@@ -1,3 +1,3 @@
1
1
  module Stockfighter
2
- VERSION = "0.1.4"
2
+ VERSION = "0.2.0"
3
3
  end
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.1.4
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-16 00:00:00.000000000 Z
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