scottrade 0.0.2 → 0.0.3
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.
- data/README.md +1 -0
- data/examples/basics.rb +5 -5
- data/lib/scottrade/brokerage.rb +68 -68
- data/lib/scottrade/helpers.rb +17 -0
- data/lib/scottrade/position.rb +16 -4
- data/lib/scottrade/session.rb +22 -21
- data/lib/scottrade/version.rb +1 -1
- data/tests/unit/auth.rb +6 -10
- data/tests/unit/brokerage.rb +9 -10
- data/tests/unit/helpers.rb +8 -0
- metadata +4 -2
data/README.md
CHANGED
@@ -4,6 +4,7 @@ Very basic gem for accessing Scottrade account information including balances an
|
|
4
4
|
|
5
5
|
**This software comes with no warranty and you use it at your own risk.**
|
6
6
|
|
7
|
+
[](https://codeclimate.com/github/nolanbrown/scottrade)
|
7
8
|
|
8
9
|
## Installation
|
9
10
|
|
data/examples/basics.rb
CHANGED
@@ -12,14 +12,14 @@ rescue StandardError => e
|
|
12
12
|
exit 1
|
13
13
|
end
|
14
14
|
|
15
|
-
begin
|
15
|
+
#begin
|
16
16
|
scottrade.brokerage.update_accounts
|
17
17
|
scottrade.brokerage.update_positions
|
18
18
|
|
19
|
-
rescue StandardError => e
|
20
|
-
|
21
|
-
|
22
|
-
end
|
19
|
+
# rescue StandardError => e
|
20
|
+
# puts e
|
21
|
+
# exit 1
|
22
|
+
# end
|
23
23
|
|
24
24
|
puts scottrade.brokerage.account_balance
|
25
25
|
##
|
data/lib/scottrade/brokerage.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'money'
|
2
2
|
require_relative 'account'
|
3
3
|
require_relative 'position'
|
4
|
+
require_relative 'helpers'
|
4
5
|
|
5
6
|
module Scottrade
|
6
7
|
class Brokerage
|
8
|
+
include Scottrade::Helpers
|
7
9
|
|
8
10
|
attr_reader :total_value, :total_cash_balance, :yesterday_total_cash_balance, :available_free_cash_blanace, :account_balance
|
9
11
|
attr_reader :total_market_value_with_options, :total_market_value_without_options, :yesterday_total_market_value
|
@@ -12,96 +14,94 @@ module Scottrade
|
|
12
14
|
attr_reader :accounts, :positions
|
13
15
|
attr_reader :current_market_value, :todays_percent_change, :todays_value_change
|
14
16
|
|
17
|
+
KEYS_TO_VARIABLES = {
|
18
|
+
# accounts data keys
|
19
|
+
"TotalAccountValue" => { :key => :total_value, :is_money => true },
|
20
|
+
"TotalMoneyBalance" => { :key => :total_cash_balance, :is_money => true },
|
21
|
+
"YesterdayTotalMoneyBalance" => { :key => :yesterday_total_cash_balance, :is_money => true },
|
22
|
+
"AvailableFreeCash" => { :key => :available_free_cash_blanace, :is_money => true },
|
23
|
+
"TotalMarketValueWithOptions" => { :key => :total_market_value_with_options, :is_money => true },
|
24
|
+
"TotalMarketValueNoOptions" => { :key => :total_market_value_without_options, :is_money => true },
|
25
|
+
"YesterdayTotalMarketValue" => { :key => :yesterday_total_market_value, :is_money => true },
|
26
|
+
"TotalSettledFunds" => { :key => :total_settled_funds, :is_money => true },
|
27
|
+
"TotalUnsettledSells" => { :key => :total_unsettled_sells, :is_money => true },
|
28
|
+
"FundsAvailableToBuyNonMarginables" => { :key => :funds_available_to_buy_non_marginables, :is_money => true },
|
29
|
+
"FundsAvailableToBuyMarginables" => { :key => :funds_available_to_buy_marginables, :is_money => true },
|
30
|
+
"FundsAvailableToBuyOptions" => { :key => :funds_available_to_buy_options, :is_money => true },
|
31
|
+
"FundsAvailableToBuyMutualFunds" => { :key => :funds_available_to_buy_mutual_funds, :is_money => true },
|
32
|
+
"FundsAvailableForWithdraw" => { :key => :funds_available_for_withdraw, :is_money => true },
|
33
|
+
"TodaysChangeApproxLiquidationValNoOptions" => { :key => :approximate_liquidation_value, :is_money => true },
|
34
|
+
"BrokerageAccountBalance" => { :key => :account_balance, :is_money => true },
|
35
|
+
# positions data keys
|
36
|
+
"totalMktValue" => { :key => :current_market_value, :is_money => false },
|
37
|
+
"totalPctChange" => { :key => :todays_percent_change, :is_money => false },
|
38
|
+
"toalPriceChange" => { :key => :todays_value_change, :is_money => false },
|
39
|
+
}
|
40
|
+
|
41
|
+
|
15
42
|
def initialize(session)
|
16
43
|
@session = session
|
17
44
|
end
|
18
45
|
|
19
|
-
# def positions
|
20
|
-
#
|
21
|
-
# end
|
22
|
-
# def accounts
|
23
|
-
# end
|
24
|
-
|
25
46
|
def update_accounts
|
26
|
-
params =
|
27
|
-
params["channel"] = "rc"
|
28
|
-
params["appID"] = "Scottrade"
|
29
|
-
params["rcid"] = "iPhone"
|
30
|
-
params["cacheid"] = ""
|
31
|
-
params["platform"] = "iPhone"
|
32
|
-
params["appver"] = "1.1.4"
|
33
|
-
params["useCachedData"] = "false"
|
47
|
+
params = request_parameters("GetFrontEndMoneyBalances")
|
34
48
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
@
|
42
|
-
|
43
|
-
|
44
|
-
@total_market_value_with_options = Money.parse parsed_response["TotalMarketValueWithOptions"]
|
45
|
-
@total_market_value_without_options = Money.parse parsed_response["TotalMarketValueNoOptions"]
|
46
|
-
@yesterday_total_market_value = Money.parse parsed_response["YesterdayTotalMarketValue"]
|
47
|
-
@total_settled_funds = Money.parse parsed_response["TotalSettledFunds"]
|
48
|
-
@total_unsettled_sells = Money.parse parsed_response["TotalUnsettledSells"]
|
49
|
-
@funds_available_to_buy_non_marginables = Money.parse parsed_response["FundsAvailableToBuyNonMarginables"]
|
50
|
-
@funds_available_to_buy_marginables = Money.parse parsed_response["FundsAvailableToBuyMarginables"]
|
51
|
-
@funds_available_to_buy_options = Money.parse parsed_response["FundsAvailableToBuyOptions"]
|
52
|
-
@funds_available_to_buy_mutual_funds = Money.parse parsed_response["FundsAvailableToBuyMutualFunds"]
|
53
|
-
@funds_available_for_withdraw = Money.parse parsed_response["FundsAvailableForWithdraw"]
|
54
|
-
@approximate_liquidation_value = Money.parse parsed_response["TodaysChangeApproxLiquidationValNoOptions"]
|
55
|
-
@account_balance = Money.parse parsed_response["BrokerageAccountBalance"]
|
56
|
-
|
57
|
-
@accounts = []
|
58
|
-
unparsed_accounts = parsed_response["AccTypeBalances"]
|
59
|
-
unparsed_accounts.each{|acct|
|
60
|
-
@accounts.push Account.new(acct)
|
61
|
-
}
|
62
|
-
|
63
|
-
elsif parsed_response["msg"]
|
64
|
-
raise RequestError, parsed_response["msg"]
|
65
|
-
else
|
66
|
-
raise RequestError
|
67
|
-
end
|
49
|
+
response = session_post(params)
|
50
|
+
set_variables_from_response(response)
|
51
|
+
|
52
|
+
@accounts = []
|
53
|
+
unparsed_accounts = response["AccTypeBalances"]
|
54
|
+
unparsed_accounts.each{|acct|
|
55
|
+
@accounts.push Account.new(acct)
|
56
|
+
}
|
57
|
+
|
68
58
|
end
|
69
59
|
|
70
60
|
def update_positions
|
71
|
-
params =
|
72
|
-
params["channel"] = "rc"
|
73
|
-
params["appID"] = "Scottrade"
|
74
|
-
params["rcid"] = "iPhone"
|
75
|
-
params["cacheid"] = ""
|
76
|
-
params["platform"] = "iPhone"
|
77
|
-
params["appver"] = "1.1.4"
|
78
|
-
|
79
|
-
params["useCachedData"] = "false"
|
61
|
+
params = request_parameters("GetPositions_v2")
|
80
62
|
params["startRow"] = "0"
|
81
63
|
params["noOfRows"] = "1000"
|
82
64
|
params["returnRealTimeMktValue"] = "true"
|
83
65
|
|
84
66
|
params["serviceID"] = "GetPositions_v2"
|
85
|
-
|
67
|
+
|
68
|
+
response = session_post(params)
|
69
|
+
|
70
|
+
set_variables_from_response(response)
|
71
|
+
|
72
|
+
@positions = []
|
73
|
+
all_positions = response["Positions"]
|
74
|
+
all_positions.each{|pos|
|
75
|
+
@positions.push Position.new(pos)
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
def session_post(params)
|
86
81
|
response = @session.post(params)
|
87
82
|
parsed_response = JSON.parse(response.body)
|
88
83
|
if parsed_response["error"] == "false"
|
89
|
-
|
90
|
-
@current_market_value = parsed_response["totalMktValue"]
|
91
|
-
@todays_percent_change = parsed_response["totalPctChange"]
|
92
|
-
@todays_value_change = parsed_response["toalPriceChange"]
|
93
|
-
|
94
|
-
@positions = []
|
95
|
-
all_positions = parsed_response["Positions"]
|
96
|
-
all_positions.each{|pos|
|
97
|
-
@positions.push Position.new(pos)
|
98
|
-
}
|
99
|
-
|
84
|
+
return parsed_response
|
100
85
|
elsif parsed_response["msg"]
|
101
86
|
raise RequestError, parsed_response["msg"]
|
102
87
|
else
|
103
88
|
raise RequestError
|
104
89
|
end
|
105
90
|
end
|
91
|
+
|
92
|
+
def set_variables_from_response(response)
|
93
|
+
response.each{|key,value|
|
94
|
+
settings = KEYS_TO_VARIABLES[key]
|
95
|
+
if settings
|
96
|
+
if settings[:is_money]
|
97
|
+
begin
|
98
|
+
value = Money.parse value
|
99
|
+
rescue
|
100
|
+
end
|
101
|
+
end
|
102
|
+
instance_variable_set("@#{settings[:key].to_s}", value)
|
103
|
+
end
|
104
|
+
}
|
105
|
+
end
|
106
106
|
end
|
107
107
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
module Scottrade
|
3
|
+
module Helpers
|
4
|
+
def request_parameters(serviceID)
|
5
|
+
params = {}
|
6
|
+
params["channel"] = "rc"
|
7
|
+
params["appID"] = "Scottrade"
|
8
|
+
params["rcid"] = "iPhone"
|
9
|
+
params["cacheid"] = ""
|
10
|
+
params["platform"] = "iPhone"
|
11
|
+
params["appver"] = "1.1.4"
|
12
|
+
params["useCachedData"] = "false"
|
13
|
+
params["serviceID"] = serviceID
|
14
|
+
params
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/scottrade/position.rb
CHANGED
@@ -4,19 +4,31 @@ module Scottrade
|
|
4
4
|
attr_reader :symbol, :display_symbol, :quantity, :previous_market_close_value, :account_type, :cusip, :security_description
|
5
5
|
attr_reader :security_class, :previous_close_price, :realTimePrice, :real_time_price, :real_time_market_value, :price_change
|
6
6
|
|
7
|
-
def initialize(details)
|
7
|
+
def initialize(details)
|
8
8
|
@symbol = details["symbol"]
|
9
9
|
@display_symbol = details["displaySymbol"]
|
10
10
|
@quantity = details["quantity"]
|
11
|
-
@previous_market_close_value = Money.parse(details["prevCloseMktValue"])
|
12
11
|
@account_type = details["accType"]
|
13
12
|
@cusip = details["cusip"]
|
14
13
|
@security_description = details["securityDescription"]
|
15
14
|
@security_class = details["SecurityClass"]
|
16
15
|
@previous_close_price = details["previousClosePrice"]
|
17
16
|
@real_time_price = details["realTimePrice"]
|
18
|
-
|
19
|
-
|
17
|
+
begin
|
18
|
+
@price_change = Money.parse details["priceChange"].split("\n")[0]
|
19
|
+
rescue
|
20
|
+
@price_change = Money.parse("$0.00")
|
21
|
+
end
|
22
|
+
begin
|
23
|
+
@previous_market_close_value = Money.parse(details["prevCloseMktValue"])
|
24
|
+
rescue
|
25
|
+
@previous_market_close_value = Money.parse("$0.00")
|
26
|
+
end
|
27
|
+
begin
|
28
|
+
@real_time_market_value = Money.parse(details["RealTimeMktValue"])
|
29
|
+
rescue
|
30
|
+
@previous_market_close_value = Money.parse("$0.00")
|
31
|
+
end
|
20
32
|
end
|
21
33
|
end
|
22
34
|
end
|
data/lib/scottrade/session.rb
CHANGED
@@ -2,9 +2,11 @@ require 'json'
|
|
2
2
|
|
3
3
|
require_relative 'base'
|
4
4
|
require_relative 'error'
|
5
|
+
require_relative 'helpers'
|
5
6
|
|
6
7
|
module Scottrade
|
7
8
|
class Session < Base
|
9
|
+
include Scottrade::Helpers
|
8
10
|
|
9
11
|
attr_reader :encrypted_id, :mask_id
|
10
12
|
|
@@ -17,46 +19,45 @@ module Scottrade
|
|
17
19
|
return (@cookies != nil)
|
18
20
|
end
|
19
21
|
def authenticate
|
20
|
-
params =
|
21
|
-
params["appID"] = "Scottrade"
|
22
|
+
params = request_parameters("VerifyLogin")
|
22
23
|
params["appName"] = "ScottradeMobileApplication"
|
23
|
-
params["rcid"] = "iPhone"
|
24
|
-
params["osName"] = "iPhone"
|
25
|
-
params["platform"] = "iPhone"
|
26
|
-
params["cacheid"] = ""
|
27
|
-
params["osVer"] = "6"
|
28
|
-
params["appver"] = "1.1.4"
|
29
24
|
params["appVer"] = "1.1.4"
|
30
25
|
params["isRemAcc"] = "true"
|
31
26
|
params["page"] = "LogIn"
|
32
|
-
params["serviceID"] = "VerifyLogin"
|
33
|
-
params["channel"] = "rc"
|
34
27
|
params["langId"] = "English"
|
35
28
|
|
36
29
|
params["acc"] = @account
|
37
30
|
params["pwd"] = @password
|
38
31
|
params["isEncrypted"] = "false"
|
39
32
|
|
40
|
-
response =
|
33
|
+
response = authentication_post(params)
|
41
34
|
all_cookies = response.get_fields('set-cookie') # only cookies are set on valid credentials
|
42
35
|
parsed_response = JSON.parse(response.body)
|
36
|
+
|
37
|
+
@cookies = []
|
38
|
+
all_cookies.each { | cookie |
|
39
|
+
@cookies.push(cookie.split('; ')[0])
|
40
|
+
}
|
41
|
+
@encrypted_dd = parsed_response["encryptedId"]
|
42
|
+
@mask_id = parsed_response["maskId"]
|
43
|
+
|
44
|
+
return self
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def authentication_post(params)
|
49
|
+
response = post(params)
|
50
|
+
parsed_response = JSON.parse(response.body)
|
43
51
|
if parsed_response["error"] == "false" and !parsed_response.has_key?("errmsg")
|
44
|
-
|
45
|
-
all_cookies.each { | cookie |
|
46
|
-
cookies.push(cookie.split('; ')[0])
|
47
|
-
}
|
48
|
-
@cookies = cookies
|
49
|
-
@encrypted_dd = parsed_response["encryptedId"]
|
50
|
-
@mask_id = parsed_response["maskId"]
|
51
|
-
|
52
|
-
return self
|
52
|
+
return response
|
53
53
|
elsif parsed_response["msg"]
|
54
54
|
raise AuthenticationError, parsed_response["msg"]
|
55
55
|
elsif parsed_response["errmsg"]
|
56
56
|
raise AuthenticationError, parsed_response["errmsg"]
|
57
57
|
else
|
58
58
|
raise AuthenticationError
|
59
|
-
end
|
59
|
+
end
|
60
60
|
end
|
61
|
+
|
61
62
|
end
|
62
63
|
end
|
data/lib/scottrade/version.rb
CHANGED
data/tests/unit/auth.rb
CHANGED
@@ -1,20 +1,16 @@
|
|
1
1
|
require 'test/unit'
|
2
2
|
require 'rack/test'
|
3
|
-
|
3
|
+
require_relative '../../lib/scottrade'
|
4
|
+
require_relative 'helpers'
|
4
5
|
|
5
6
|
class AuthenticationTest < Test::Unit::TestCase
|
6
7
|
include Rack::Test::Methods
|
7
|
-
|
8
|
+
include ScottradeUnitTestHelpers
|
9
|
+
|
8
10
|
def test_positive_authentication
|
9
|
-
|
10
|
-
assert_nothing_raised Scottrade::AuthenticationError do
|
11
|
-
scottrade.authenticate
|
12
|
-
end
|
11
|
+
authenticate(ENV["SCOTTRADE_ACCOUNT"],ENV["SCOTTRADE_PASSWORD"])
|
13
12
|
end
|
14
13
|
def test_negative_authentication
|
15
|
-
|
16
|
-
assert_raise Scottrade::AuthenticationError do
|
17
|
-
scottrade.authenticate
|
18
|
-
end
|
14
|
+
authenticate("555555555","password")
|
19
15
|
end
|
20
16
|
end
|
data/tests/unit/brokerage.rb
CHANGED
@@ -1,25 +1,24 @@
|
|
1
1
|
require 'test/unit'
|
2
2
|
require 'rack/test'
|
3
|
-
|
3
|
+
require_relative 'helpers'
|
4
|
+
require_relative '../../lib/scottrade'
|
5
|
+
|
4
6
|
class AuthenticationTest < Test::Unit::TestCase
|
5
7
|
include Rack::Test::Methods
|
6
|
-
|
8
|
+
include ScottradeUnitTestHelpers
|
7
9
|
def test_brokerage_balances
|
8
|
-
|
9
|
-
|
10
|
-
scottrade.authenticate
|
11
|
-
end
|
10
|
+
authenticate(ENV["SCOTTRADE_ACCOUNT"],ENV["SCOTTRADE_PASSWORD"])
|
11
|
+
|
12
12
|
assert_nothing_raised Scottrade::RequestError do
|
13
13
|
scottrade.brokerage.update_accounts
|
14
14
|
end
|
15
15
|
end
|
16
16
|
def test_brokerage_positions
|
17
|
-
|
18
|
-
|
19
|
-
scottrade.authenticate
|
20
|
-
end
|
17
|
+
authenticate(ENV["SCOTTRADE_ACCOUNT"],ENV["SCOTTRADE_PASSWORD"])
|
18
|
+
|
21
19
|
assert_nothing_raised Scottrade::RequestError do
|
22
20
|
scottrade.brokerage.update_positions
|
23
21
|
end
|
24
22
|
end
|
23
|
+
|
25
24
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scottrade
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: money
|
@@ -45,6 +45,7 @@ files:
|
|
45
45
|
- lib/scottrade/base.rb
|
46
46
|
- lib/scottrade/brokerage.rb
|
47
47
|
- lib/scottrade/error.rb
|
48
|
+
- lib/scottrade/helpers.rb
|
48
49
|
- lib/scottrade/position.rb
|
49
50
|
- lib/scottrade/quote.rb
|
50
51
|
- lib/scottrade/session.rb
|
@@ -52,6 +53,7 @@ files:
|
|
52
53
|
- scottrade.gemspec
|
53
54
|
- tests/unit/auth.rb
|
54
55
|
- tests/unit/brokerage.rb
|
56
|
+
- tests/unit/helpers.rb
|
55
57
|
homepage: https://github.com/nolanbrown/scottrade
|
56
58
|
licenses: []
|
57
59
|
post_install_message:
|