Created
February 23, 2014 23:36
-
-
Save jefflunt/9178947 to your computer and use it in GitHub Desktop.
Basic ruby script to pull active listings and match against a strategy every 300 milliseconds (max)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
source "https://rubygems.org" | |
gem 'curb' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1. Install Ruby 2.1.0 (there are tutorials for this - if you're new, try the | |
tool called RVM - http://rvm.io | |
If you're installing Ruby on Windows, god help you. Hopefully you're either | |
on Mac or Linux. Can't help you with Windows. | |
2. Put these files all into a single folder | |
3. Go into that folder | |
4. Type 'bundle install' | |
If you get errors about not being able to find 'bundler', then type: | |
gem install bundler | |
5. Type 'ruby lender.rb' to run the script | |
6. Press Ctrl+C to kill the script (or else it will run forever) | |
Sample output from the script is in the 'Sample output' file |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Script to interact with Prosper's API | |
require 'json' | |
require 'time' | |
require 'curb' | |
# Init | |
USER = ENV['PROSPER_USER'] | |
PASS = ENV['PROSPER_PASS'] | |
STRATEGIES = JSON.parse(File.read('./strategies.json')) | |
@queries = { | |
account: Curl::Easy.new('https://api.prosper.com/api/Account'), | |
investments: Curl::Easy.new('https://api.prosper.com/api/Investments'), | |
active_listings: Curl::Easy.new('https://api.prosper.com/api/Listings') | |
} | |
@queries.each do |symbol, query| | |
query.http_auth_types = :basic | |
query.username = USER | |
query.password = PASS | |
end | |
## | |
# Returns a string representation of the number of seconds (with millisecond | |
# precision) since the specified start time. | |
def seconds_since(start_time) | |
"#{(Time.now-start_time).to_s[0..4]}s" | |
end | |
## | |
# Returns a JSON object containing the results of the query lookup, or nil if | |
# the query failed. | |
def perform_query(query_symbol) | |
start_time = Time.now | |
@queries[query_symbol].perform | |
puts "Query time: #{seconds_since(start_time)}" | |
@queries[query_symbol].response_code == 200 ? JSON.parse(@queries[query_symbol].body_str) : nil | |
end | |
## | |
# Returns the number of strategies that match the provided listing JSON string. | |
# This number maps directly to the number of buy orders to be placed under the | |
# current users' account. | |
def strategy_matches(listing_json) | |
matches = [] | |
STRATEGIES.each do |s| | |
matches << s if s["active"] && s["match_criterion"].all?{|data_point_name, acceptable_values| acceptable_values.include?(listing_json[data_point_name]) } | |
end | |
matches | |
end | |
## | |
# Print the investments JSON object nicely for human consumption. | |
def print_investments(investments_json) | |
start_time = Time.now | |
printf "%-10s | %-6s | %-20s | %8s | %8s\n", "Date", "Amount", "Status", "Listing", "Loan" | |
printf "----------------------------------------------------------------\n" | |
investments_json.each do |i| | |
loan_number = case i["ListingStatusDescription"] | |
when "Completed" | |
i["LoanNumber"] | |
when "Cancelled" | |
i["ListingStatusDescription"] = "XX" | |
"XX" | |
else | |
"--" | |
end | |
printf("%10s | $%5d | %-20s | %8s | %8s\n", i["InvestmentDate"][0..9], i["Amount"], i["ListingStatusDescription"][0..19], i["ListingNumber"], loan_number) | |
end | |
puts "Print time: #{seconds_since(start_time)}" | |
nil | |
end | |
## | |
# Print the active listings JSON object nicely for human consumption. | |
def print_active_listings(listings_json) | |
start_time = Time.now | |
printf "%7s | %4s | %4s | %4s | %4s | %8s | %7s | %6s | %5s | %-5s\n", "BUY", "Pop", "% Fd", "Age", "Term", "Listing", "FICO", "Rating", "Score", "ER" | |
printf "----------------------------------------------------------------------------------\n" | |
listings_json.each do |l| | |
matches = strategy_matches(l) | |
percent_funded = l["PercentFunded"] | |
age = Time.now - Time.parse(l["ListingCreationDate"]) | |
# Magic formula that make the popularity approach 500 when the listing is | |
# <1ms old, but drop to zero by the time it's 24 hours old | |
popularity = (((-25 * Math::log(age))+284.1685739) * percent_funded).to_i | |
popularity = 0 if popularity < 0 | |
printf "%7s | %4s | %4d | %3s | %4s | %8s | %7s | %6s | %5s | %5s\%\n", matches.collect{|m| m["id"]}.join(','), popularity.to_s, (percent_funded*100).to_i, (age/86400).to_s[0..3], l["ListingTerm"], l["ListingNumber"], l["FICOScore"], l["ProsperRating"], l["ProsperScore"], (l["EstimatedReturn"]*100).to_s[0..4] | |
end | |
puts "Print time: #{seconds_since(start_time)}" | |
nil | |
end | |
begin | |
print_active_listings(perform_query(:active_listings).sort_by{|l| l["ListingCreationDate"]}) | |
sleep 0.3 | |
end while true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The fields listed here are: | |
- BUY (if a strategy name is shown in this column, then that strategy matches that listing | |
- Pop (a rough guess at the popularity of that listing, based on its age and its percentage funded) | |
- % Fd (Percentage funded) | |
- Age (age since the listing was created - NOTE: probably not the same as the age since the listing | |
was made public during feeding time) | |
- Term (36 or 60 months / 3 or 5 year) | |
- Listing (the listing ID) | |
- FICO (the borrow's FICO score range) | |
- Rating (the Prosper Rating) | |
- Score (the Prosper Score) | |
- ER (Estimated Return - pulled from the API - NOT my own calculation) | |
Query time: 1.477s | |
BUY | Pop | % Fd | Age | Term | Listing | FICO | Rating | Score | ER | |
---------------------------------------------------------------------------------- | |
| 0 | 76 | 10.1 | 60 | 1191512 | 820-850 | A | 11 | 6.081% | |
| 0 | 39 | 6.99 | 36 | 1212813 | 760-779 | A | 11 | 5.568% | |
| 0 | 33 | 5.08 | 36 | 1161322 | 740-759 | AA | 10 | 4.261% | |
| 0 | 89 | 5.00 | 36 | 1221276 | 680-699 | A | 8 | 5.879% | |
| 0 | 88 | 4.96 | 36 | 1162330 | 760-779 | A | 8 | 6.705% | |
| 0 | 61 | 4.22 | 36 | 1165903 | 700-719 | AA | 10 | 4.553% | |
| 0 | 38 | 3.86 | 36 | 1169683 | 700-719 | AA | 8 | 4.929% | |
| 0 | 73 | 3.35 | 36 | 1200347 | 740-759 | A | 11 | 5.342% | |
| 0 | 49 | 3.03 | 36 | 1201904 | 760-779 | AA | 10 | 4.261% | |
| 0 | 71 | 2.68 | 60 | 1202927 | 820-850 | A | 10 | 5.879% | |
| 0 | 90 | 2.42 | 36 | 1170511 | 680-699 | A | 7 | 6.499% | |
| 0 | 35 | 2.38 | 36 | 1170703 | 740-759 | AA | 10 | 4.261% | |
| 0 | 70 | 2.34 | 36 | 1226103 | 660-679 | A | 8 | 6.081% | |
| 0 | 34 | 2.28 | 36 | 1226514 | 720-739 | AA | 8 | 4.929% | |
| 0 | 94 | 2.23 | 36 | 1227039 | 720-739 | A | 7 | 6.705% | |
| 0 | 42 | 2.22 | 36 | 1227060 | 720-739 | A | 10 | 5.568% | |
| 0 | 35 | 2.20 | 36 | 1227270 | 760-779 | AA | 6 | 4.929% | |
| 0 | 33 | 2.17 | 36 | 1171417 | 760-779 | AA | 10 | 4.806% | |
| 0 | 28 | 2.09 | 36 | 1228101 | 780-799 | AA | 7 | 4.929% | |
| 0 | 22 | 2.04 | 36 | 1171837 | 760-779 | AA | 9 | 4.261% | |
| 0 | 64 | 1.46 | 36 | 1172950 | 800-819 | AA | 6 | 4.806% | |
| 0 | 19 | 1.40 | 36 | 1173310 | 720-739 | AA | 10 | 4.261% | |
| 0 | 43 | 1.20 | 36 | 1175035 | 720-739 | A | 7 | 5.342% | |
| 0 | 40 | 1.19 | 36 | 1175104 | 740-759 | AA | 9 | 4.553% | |
| 0 | 49 | 1.12 | 36 | 1175701 | 720-739 | AA | 11 | 4.806% | |
| 0 | 29 | 1.12 | 36 | 1175704 | 720-739 | AA | 8 | 4.929% | |
| 0 | 80 | 0.95 | 36 | 1176559 | 780-799 | AA | 10 | 4.553% | |
| 1 | 56 | 0.92 | 36 | 1176625 | 740-759 | A | 9 | 5.568% | |
| 0 | 22 | 0.90 | 36 | 1176715 | 720-739 | AA | 10 | 4.261% | |
| 3 | 39 | 0.73 | 36 | 1177198 | 740-759 | AA | 8 | 4.806% | |
Print time: 0.003s |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{ | |
"id": "NSR-001", | |
"name": "Bill Payers", | |
"active": true, | |
"match_criterion": { | |
"ProsperRating": ["C", "E", "HR"], | |
"FICOScore": ["640-659", "660-679", "680-699"], | |
"PublicRecordsLast10Years": [0], | |
"InquiriesLast6Months": [0] | |
} | |
} | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment