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 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