January 2011

Before working with Rhett on Cam.ly, I was living in the Bay Area trying to bootstrap my own startup (2dparts.com). But it wasn't getting traction, and I was fast running out of money. I needed a source of income that would pay my living expenses but not interfere with my startup. I came up with the idea of Craigslist arbitrage.

The basic idea was to buy undervalued items on Craigslist and sell them for more. Just as financial analysts takes advantage of price fluctuations and imperfect information in the stock markets, I wanted to take advantage of similar imperfections in the Craigslist market. I assumed the Craigslist market would be much less efficient than the stock markets since there are less people making their living by buying and selling Craigslist items. Moreover, the sellers on Craigslist were likely much more in need of "liquidity", the magic word that financial analysts use to justify their jobs.

For Craigslist arbitrage to be profitable, you must be able to find a large number of potentially undervalued items, and you must be able to value them appropriately. Arbitrage on higher priced items is preferable because as the price of the item increases so does the price difference. At first I wanted to do Craigslist arbitrage with cars. I thought with cars being ~$5000 I could easily make $500 by finding a good deal. This idea was flawed because the legal mess with buying and selling cars would easily cost $500 in time and money. The next thought was Macbooks. Perfect. With the priced at ~$1000, I could make a decent amount per transaction. Also unlike PC's, Macs are similar enough that it would be easier to pin a price using the Mac's specs (i.e. processor speed, ram, hd space). With PC's the brand would be too much of factor, and it would be too hard to find enough of one brand. Above all, second hand PC's seemed scary to me. I would rather not deal with Windows.

Here's the first mac I bought:

The exciting part of buying and selling Macbooks was writing Python scripts to determine undervalued Macbooks. I wrote a Python script to scrape Craigslist and wrote a csv file with the Price, Size, GHz, Ram, HDD of each Macbook. The script uses the library urllib2 to get the html files and BeautifulSoup to parse the html. I've posted the Python script at the end. The code isn't pretty because it isn't where you create value in Craigslist arbitrage. The code and data is more for fun. I loaded the data into R and did some quick stats on it. I did a quick linear fit with the model: Price ~ Size + GHz + Ram + HDD.

The results:
\hat{P} = 57.33*Size + 1201.71*GHz + 6.8*Ram + .43*HDD - 2656.07

You can see processor speed is a powerful predictor of price even if you normalize (account for the fact that processor speed doesn't vary as much as hard disc space). This equation helps find something close to the market value of a used Mac. I used the equation to determine prices that were 2 standard deviations below the predicted price.

Here's an interesting graph from the data that proves the price difference increases with price:

The data isn't enough to find deals though you must develop an intuition. For example it quickly became apparent that a unibody Macbook was worth more than one that wasn't a unibody. The data analysis helped me quickly develop an intuition for a good deal. Eventually I could spot a deal and that took less time than analyzing data.

The data analysis is for fun. Money is made by making quick and easy deals in your favor. Use your data and intuition to find a deal and then ask to meet in person. Don't set a price over email or the phone because you haven't inspected what their selling yet. Once you make sure everything is in order you might want to bargain some off the asking price. Getting $50 off the asking price isn't crazy considering you made selling the Macbook so easy. Selling on Craigslist sucks, it's time consuming and you have to deal with flaky people that just want a deal. If the person you're buying from has ever sold anything off Craigslist they will understand its worth $50 or more for you to make the sell easy. At first I, like most Americans, hated bargining. We've grown up with set prices, so we feel like it's stealing or wrong to ask for a better price. But if you've ever taken an economics class you know valuation of anything is hard. There are no set prices. Bargining shouldn't feel wrong; it's working to find a price that both parties are comfortable with. In America we have so much privilege we accept most prices. I still hate bargining but now it doesn't feel wrong.

You got a great deal on a Macbook. Now you have to sell it. When selling you have to make your market of potential buyers as big as possible. Sell the Macbook on every marketplace you know: eBay, Craigslist, Facebook marketplace, etc... Reselling the Macbooks took a lot more time and effort than I expected. If you want to make this worth your time you have to get more than $100 per Macbook and automate the process as much as possible. I didn't do Craigslist arbitrage for long because it was not worth my time and effort. I moved on to building Cam.ly which will hopefully add more value to the world than flipping Macbooks. I like to think I learned something flipping Macbooks. Facing my social inhibitions during bargining has helped me with facing similar inhibitions during marketing and pushing a product at Cam.ly.

import urllib2
from BeautifulSoup import BeautifulSoup
import time
import csv
import re

csvwriter = csv.writer(open('macbookall3.csv', 'w'), delimiter=',')

def re2num(rexp,isint,searchspace):
	if isint:
		num=re.search(rexp,searchspace)
		try:
			num=re.search('[0-9]+',num.group(0))
			return int(num.group(0))
		except:
			return ''
	else:
		num=re.search(rexp,searchspace)
		try:
			num=re.search('\d+\.\d+',num.group(0))
			return float(num.group(0))
		except:
			return ''

def getnum(rexp,isint,searchspaces,val,n):
	if val=='':
		if n<2:
			val=re2num(rexp,isint,searchspaces[n])
		else:
			val='NotFound'
		return getnum(rexp,isint,searchspaces,val,n+1)
	else:
		return val

donec=['atlanta','austin','boston','chicago','dallas','denver','detroit','houston','lasvegas','losangeles','miami','minneapolis','newyork','philadelphia','phoenix','portland','raleigh','sacramento']
cities=['sandiego','seattle','sfbay']
count=0
for c in cities:
	http='http://%s.craigslist.org/search/sss?query=macbook+pro&catAbbreviation=sss&minAsk=800'%c
	request = urllib2.urlopen(http)
	html = request.read()
	soup=BeautifulSoup(html)

	for p in soup.findAll("p"):
		if (p.contents[1].attrs[0][0]=='href'):
			linedesc=p.contents[1].contents[0]
			link=p.contents[1].attrs[0][1]
			request = urllib2.urlopen(link)
			html = request.read()
			isoup = BeautifulSoup(html)
			d=isoup.find('div',id="userbody")
			s=d.__str__
			fulldesc=s()
			searchspaces=[linedesc,fulldesc];
			#dic={"price":['\$[0-9]+',True,''],"size":['(?![0-9.])\d\d\D',True,'']}

			price=getnum('\$[0-9]+',True,searchspaces,'',0)
			size=getnum('\D1[357]\D',True,searchspaces,'',0)
			ghz=getnum('\s\d\.\d\d?\s?[Gg][Hh]',False,searchspaces,'',0)
			ram=getnum('\D\d\s?[Gg][Bb]',True,searchspaces,'',0)
			hdd=getnum('\D\d\d\d\s?[Gg][Bb]',True,searchspaces,'',0)

			csvwriter.writerow([c,link,linedesc,price,size,ghz,ram,hdd])