New Forum

Visit the new forum at http://godelsmarket.com/bb

Tuesday, July 31, 2012

Covered Calls

There's a huge push by a certain group of "advisers" for covered call writing. It is always presented, at least it feels this way to me, as a source of free money. These picks, for instance, seem rather poor choices to me.

I haven't gotten around to doing my own in-depth analysis of covered call writing, but I read this one earlier today.  I love this quote:
"As shown, they also partially hedge in downtrends. But the best use of covered calls is if you can see into the future and pick when your stock is going to go sideways."
They are great if you know the stock isn't going to go up too much. It's because writing covered calls limits your upside. It doesn't magically make money appear out of thin air. Plus, if you're not already long the underlier, you're taking on significant downside risk. The stock can still go to zero, and you would be taking that loss. While the stock can go to infinity as well, you're limited by whatever your upside call was sold at.

The strategy is not a magic money maker. It is, if anything, a portfolio volatility reducer.

Monday, July 30, 2012

Charts and Cliff-Hanger Analysis

Can it really be that easy? No. No, it can’t. Of  course, I can’t make any comments on anything but what I see (which appears rather like an advertisement for the premium service that they offer), I have to say what I see appears somewhat misleading.

Now, I know—it is merely a short post exhibiting an interesting result, a result that seems to hold well enough for profit.  What really gets me is the lack of a legitimate disclaimer. And the question at the end. I suppose Bespoke is looking to start conversation. Maybe. Or they’re just not interested in sharing their information. Which is mostly likely the case.

I should be grateful for the small insight they are providing. Of course, I would love to see the data and the process they used to form the chart (which, yes, I could probably do on my own). But, I also would like to see something commenting on the divergence at the beginning of the year (January to April) and what some of the other presidential years looked like. Again, I’m not paying for anything from them, so what can I expect? (Maybe I’ll post some of my own analysis…if I have time).

I guess what really gets me is that I don’t believe this is enough information to go by to make a good decision to go long at the current moment.

And, now that I look at the graph (and the axes labels) I am slightly confused. But with a quick comparison to the SPX's current return anyone could sort that out...

Oh well. An interesting chart in the least--as long as you do your due diligence. 

MATLAB VWAP, Part II: Backtest

After reading some Coding Horror (this specifically), I decided I might as well begin sharing more results. Albeit not terribly useful from a trading perspective--I'll explain shortly--, here are some results utilizing a small database of GS minute values (approximately just short of two weeks).  The backtest uses an extension of the VWAP code from yesterday following the simple rules of long when the 100 minute VWAP > 500 minute VWAP and short when 100 min VWAP < 500 min VWAP. A pretty simple, standard, elementary test.

Here are the results (with image):

Return: +13.36% (rounded)

PLEASE DO NOT TRADE ON THESE RESULTS. 

As I mentioned above, this should not be used from a trading perspective for several reasons:

1) It is run on far too few data points. Perhaps it just happened to work perfectly for this interval. I have no clue if this holds. (If you would like to donate historical data, please let me know!)

2) This is done during earnings, and, as you would see if you ran this for other stocks, could be hit or miss, especially with overnight holding (and, again, especially through earnings).

3) There are plenty of stocks this does not work for. Some with similar sized returns, although negative.

4) My data could be flawed, my routine should be suspect and you should always perform tests read on the internet for yourself!

5) I am sure there are 10 more reasons.
Now, here is the "backtest" code in function form. It's for MATLAB and requires that you have some data in  a MySQL database (very easy if you use my IB Historical Data Downloader/Importer):

function sum_log_change = vwap_backtest(symbol_string)

clear close_mat
clear volume_mat
clear vwap
clear vwap_2
clear buy_sell_matrix
clear trade
clear trade_prices
clear sum_log_change

vwap_length = 100;
vwap_length_2 = 500;

format long

symbol_string

%connect to the database CHANGE PASSWORD FROM ***** TO WHATEVER YOUR PASSWORD IS!!!
conn = database('stocks','root','****','com.mysql.jdbc.Driver','jdbc:mysql://localhost:3306/stocks');

%query the symbols in the database
str_query_close = ['SELECT close, volume FROM stock_prices_minute WHERE symbol = ''',symbol_string,  ''''];
close_cell = fetch(conn, str_query_close);

close_mat = cell2mat(close_cell(:,1));
volume_mat = cell2mat(close_cell(:,2));

close_times_volume = close_mat .* volume_mat;


for i = vwap_length:length(close_times_volume)
    volume_total = 0;
    volume_price_sum = 0;
    for j = 0:(vwap_length - 1)
        volume_total = volume_total + volume_mat(i-j);
        volume_price_sum = volume_price_sum + volume_mat(i-j)*close_mat(i-j);
    end
    vwap(i-(vwap_length - 1)) = volume_price_sum / volume_total;
end


for i = vwap_length_2:length(close_times_volume)
    volume_total = 0;
    volume_price_sum = 0;
    for j = 0:(vwap_length_2 - 1)
        volume_total = volume_total + volume_mat(i-j);
        volume_price_sum = volume_price_sum + volume_mat(i-j)*close_mat(i-j);
    end
    vwap_2(i-(vwap_length_2 - 1)) = volume_price_sum / volume_total;
end


%do comparing
for i = 1:(length(close_times_volume) - (vwap_length_2 - 1))
    if vwap_2(i) < vwap(i+(vwap_length_2 - vwap_length))
        buy_sell_matrix(i) = 1;
    else
        buy_sell_matrix(i) = -1;
    end
end

buy_sell_matrix;

%calculate trade prices
for i = 1:(length(close_times_volume) - (vwap_length_2 - 1))
    if i == 1
        trades(i) = close_mat(i + vwap_length_2);
    else
        if buy_sell_matrix(i) ~= buy_sell_matrix(i-1)
            trades(i) = close_mat(i + vwap_length_2);
        elseif i == (length(close_times_volume)-(vwap_length_2 - 1))
            trades(i) = close_mat(length(close_mat));
        else
            trades(i) = 0;
        end
    end
end

trades;

j = 1;
%matrix of prices trades took place at
for i = 1:length(trades)
    if trades(i) ~= 0
        trade_prices(j) = trades(i);
        j = j + 1;
    end
end


trade_prices;

log_change = 0;
sum_log_change = 0;
%now you can calculate lognormal return
for i = 1:(length(trade_prices) - 1)
    if buy_sell_matrix(1) == 1
        if mod(i,2) == 0
            log_change = -(log(trade_prices(i+1)) - log(trade_prices(i)));
        else
            log_change = log(trade_prices(i+1)) - log(trade_prices(i));
        end
        sum_log_change = sum_log_change + log_change;
    else
        if mod(i,2)==0
            log_change = log(trade_prices(i+1)) - log(trade_prices(i));
        else
            log_change = -(log(trade_prices(i+1)) - log(trade_prices(i)));
        end
        sum_log_change = sum_log_change + log_change;
    end
end

sum_log_change;
            
        
    

x = [1:length(close_mat)];
x2 = [(vwap_length):length(close_mat)];
x3 = [(vwap_length_2):length(close_mat)];
plot(x, close_mat)
hold on
plot(x2, vwap, '-r')
hold on
plot(x3, vwap_2, '-g')

Link to previous article: MATLAB VWAP (Part I)

Saturday, July 28, 2012

MATLAB VWAP

Here's a simple MATLAB script to extract data from a MySQL Database (here, specifically one that was created using my IB historical data extractor) and plot close data along with two VWAPs (volume weighted average prices) of your desired length. It's pretty simple but could be expanded upon to backtest VWAP strategies using the created VWAP matrices. (Also, I think I fixed the way source code is displayed on this site...should now be easier to copy and paste).

Update: Here's part II.

clear close_mat
clear volume_mat
clear vwap
clear vwap_2

vwap_length = 100;
vwap_length_2 = 500;

format long

%connect to the database
conn = database('stocks','root','***','com.mysql.jdbc.Driver','jdbc:mysql://localhost:3306/stocks');

%query the symbols in the database
str_query_close = 'SELECT close, volume FROM stock_prices_minute WHERE symbol = ''GOOG''';
close_cell = fetch(conn, str_query_close);

close_mat = cell2mat(close_cell(:,1))
volume_mat = cell2mat(close_cell(:,2));

close_times_volume = close_mat .* volume_mat;


for i = vwap_length:length(close_times_volume)
    volume_total = 0;
    volume_price_sum = 0;
    for j = 0:(vwap_length - 1)
        volume_total = volume_total + volume_mat(i-j);
        volume_price_sum = volume_price_sum + volume_mat(i-j)*close_mat(i-j);
    end
    vwap(i-(vwap_length - 1)) = volume_price_sum / volume_total;
end

for i = vwap_length_2:length(close_times_volume)
    volume_total = 0;
    volume_price_sum = 0;
    for j = 0:(vwap_length_2 - 1)
        volume_total = volume_total + volume_mat(i-j);
        volume_price_sum = volume_price_sum + volume_mat(i-j)*close_mat(i-j);
    end
    vwap_2(i-(vwap_length_2 - 1)) = volume_price_sum / volume_total;
end


x = [1:length(close_mat)];
x2 = [(vwap_length):length(close_mat)];
x3 = [(vwap_length_2):length(close_mat)];
plot(x, close_mat)
hold on
plot(x2, vwap, '-r')
hold on
plot(x3, vwap_2, '-g')

Thursday, July 26, 2012

WSJ/FT Paywall Bypass

Here's a guide on how to bypass the WSJ paywall. It also works with FT.

Basically, just copy the article name you want to read and paste it into Google. Then select the article from the search results. Now, you can read it as though you had a subscription!

Wednesday, July 25, 2012

Downloading Options Data From Yahoo!

I wanted to do some volatility surfaces using Yahoo! options data. Unfortunately they don't make it as easy to grab options data as it is to grab stock data.

Here's a very nice solution. (To prevent loss, source code follows; although all credit goes to link!)

function DataOut = Get_Yahoo_Options_Data(symbolid)
%Get_Yahoo_Options_Data get Option Chain Data from Yahoo
% Get Options Chain Data from Yahoo
% DataOut = Get_Yahoo_Options_Data(symbol)
% Inputs: Symbol name as a character String
% Output:  A structure with the following fields
%       data : A 1xN cell where N is the number of Expiries available
%       ExpDates : A 1xN cell array of Expiry Dates
%       Calls  : A 1xN cell array of Call Option data for each expiry
%       Puts  : A 1xN cell array of Put Option data
%       CPHeaders : Headers for the calls and puts option data
%       Headers: Headers for the data
%       FullOptionData : A combined cell array of DataOut.data
%       Last : Last Price
% Example:
%           DataOut = Get_Yahoo_Options_Data('LVS');
% (c)tradingwithmatlab.blogspot.com
DataOut = struct;
% Construct and read the URL from Yahoo Finance Website
urlText = urlread(['http://finance.yahoo.com/q/os?s=' symbolid]);
% Try getting the Table Data from URL Text 
TableData = getTableData();
% If Empty return
if(isempty(TableData))
    return
else
    DataOut.data{1} = TableData;
end
% Get the Expiry Date for later use
DataOut.ExpDates{1} = Get_Exp_Dates();
% Get Expiry Dates that are listed in the website to construct separate
% URLS for each month
NextExpiryURL = Get_Next_Expiry_URL();
if(isempty(NextExpiryURL))
   return
end

% Now read Option Tables of each Expiry month
for ik = 1:length(NextExpiryURL)
    urlText = urlread(NextExpiryURL{ik});
    DataOut.ExpDates{ik+1} = Get_Exp_Dates();
    DataOut.data{ik+1} = getTableData();
end
% Clean Up
% Convert the strings into numbers 
f = @(x)[x(:,1) num2cell(str2double(x(:,[2:8]))) x(:,9) num2cell(str2double(x(:,10:end)))];
DataOut.data = cellfun(f,DataOut.data,'uni',false);

goodDataIdx = (~cellfun('isempty',DataOut.data));
DataOut.data = DataOut.data(goodDataIdx );
DataOut.ExpDates = DataOut.ExpDates(goodDataIdx );
% Separate the data into Calls, Puts, Headers
DataOut.Calls = cellfun(@(x) x(:,[1 8 2:7]),DataOut.data,'uni',false);
DataOut.Puts = cellfun(@(x) x(:,[9 8 10:end]),DataOut.data,'uni',false);
DataOut.CPHeaders = {'Symbol','Strike','Last','Change','Bid','Ask','Volume','Open Int'};
DataOut.Headers = {'Symbol','Last','Change','Bid','Ask','Volume','Open Int','Strike',...
    'Symbol','Last','Change','Bid','Ask','Volume','Open Int'};
DataOut.FullOptionData = [DataOut.Headers ; cat(1,DataOut.data{:})];
% Get the Last Price
DataOut.Last = str2num(urlread(['http://download.finance.yahoo.com/d/quotes.csv?s=' symbolid '&f=l1&e=.csv']));

%% Get_Next_Expiry_URL
    function NextExpiry = Get_Next_Expiry_URL()
        % Get the start and end indices and look for a particular text
        Start = regexp(urlText,'View By Expiration:','end');
        end1 = regexp(urlText,'Return to Stacked View...','start');
        
        Data = urlText(Start:end1);
        Data=Data(2:end);
        % Trim the data
        Data=strtrim(Data);
        % Split the data into new lines
        newlines = regexp(Data, '[^\n]*', 'match');
        expr = '<(\w+).*?>.*?</\1>';
        if(isempty(newlines))
            NextExpiry = {};
            return
        end
        % Get the matches of particular expression
        [tok mat] = regexp(newlines{1}, expr, 'tokens', 'match');
        id1= regexp(mat{1},'</b>','start')-1;
        month{1} = mat{1}(4:id1);
        %Month and Next Expiries
        for j = 2:length(mat)-1
            id2 = regexp(mat{j},'">','end');
            id3 = regexp(mat{j},'</a','start');
            if(isempty(id3))
                return
            end
            month{j} = mat{j}(id2+1:id3-1);
            id4 = regexp(mat{j},'"','start');
            NextExpiry{j-1} = ['http://finance.yahoo.com' mat{j}(id4(1)+1:id4(2)-1)]; %#ok<*AGROW>
            NextExpiry{j-1} = regexprep(NextExpiry{j-1},'amp;','');
        end
        
    end
%% Get_Exp_Dates

    function ExpDates = Get_Exp_Dates()
        
        id1 = regexp(urlText,'Options Expiring','end');
        id2 = regexp((urlText(id1+1:id1+51)),'</b>','start');
        ExpDates = strtrim(urlText(id1+1:id1+1+id2-2));
        ExpDates=datestr(datenum(ExpDates,'dddd, mmmm dd,yyyy'));
    end

%% getTableData
    function out = getTableData()
        Main_Pattern = '.*?</table><table[^>]*>(.*?)</table';
        Tables = regexp(urlText, Main_Pattern, 'tokens');
        out = {};
        if(isempty(Tables))
            return
        end
        try
        for TableIdx = 1 : length(Tables)
            
            %Establish a row index
            rowind = 0;
            
            
            % Build cell aray of table data
            
                rows = regexpi(Tables{TableIdx}{:}, '<tr.*?>(.*?)</tr>', 'tokens');
                for rowsIdx = 1:numel(rows)
                    colind = 0;
                    if (isempty(regexprep(rows{rowsIdx}{1}, '<.*?>', '')))
                        continue
                    else
                        rowind = rowind + 1;
                    end
                    
                    headers = regexpi(rows{rowsIdx}{1}, '<th.*?>(.*?)</th>', 'tokens');
                    if ~isempty(headers)
                        for headersIdx = 1:numel(headers)
                            colind = colind + 1;
                            data = regexprep(headers{headersIdx}{1}, '<.*?>', '');
                            if (~strcmpi(data,'&nbsp;'))
                                out{rowind,colind} = strtrim(data);
                            end
                        end
                        continue
                    end
                    cols = regexpi(rows{rowsIdx}{1}, '<td.*?>(.*?)</td>', 'tokens');
                    for colsIdx = 1:numel(cols)
                        if(rowind==1)
                            if(isempty(cols{colsIdx}{1}))
                                continue
                            else
                                colind = colind + 1;
                            end
                        else
                            colind = colsIdx;
                        end
                        % The following code is required to get the sign
                        % of the change in Bid ask prices
                        data = regexprep(cols{colsIdx}{1}, '&nbsp;', ' ');
                        down=false;
                        % If Down is found then it is negative
                        if(~isempty(regexp(data,'"Down"', 'once')))
                            down=true;
                        end
                        data = regexprep(data, '<.*?>', '');
                        if(down)
                            data = ['-' strtrim(data)];
                        end
                        if (~isempty(data))
                            out{rowind,colind} = strtrim(data) ;
                        end
                    end % colsIdx
                end
                
                
        end
        out = out(3:end,:);
        catch %M  %#ok<CTCH> This depends on which version of matlab you are using
               %M.stack
        end
    end
end

Tuesday, July 24, 2012

Import IB Historical Data into MySQL

Here's the code to import the csv files you created using the IB Historical Data Downloader (assuming you put all the files into a folder called "csv", have the below python file one folder above, and are running your MySQL server at localhost, with user root and database "stocks". Make sure to change the password to whatever you're using.) Also, you need to have the MySQLdb module installed. Check out the last post to see an easy way to do that.
import MySQLdb
import os
db = MySQLdb.connect(host='localhost', user='root',passwd='*****', db='stocks')
cur = db.cursor()
path = 'csv/'
listing = os.listdir(path)
for infile in listing:
    cur.execute("load data local infile 'csv/" + infile + "' into table `stocks`.`stock_prices_minute` fields terminated by ',' lines terminated by '\n' (`symbol`,`date`,`open`,`high`,`low`,`close`,`volume`);")
    db.commit()
    print "Symbol: " + infile

Installing MySQLdb Python Module

If you are running Python on Windows and want to install the MySQL python module, check out http://www.lfd.uci.edu/~gohlke/pythonlibs/. Go down to MySQL-python and select the file that corresponds to your version of Python (2.6,2.7,3.2) and Windows (x86 or 64). Double click, install, and you're good to go.

Non-GUI IB Historical Data Downloader

Here's some code to download quotes for the constituents of the S&P500 through Interactive Brokers' API using Python 2.7 and IbPy.

It will pause for 10 seconds after each request so that you won't go over the 60 symbol a minute limit. Also, it keeps track of which symbols you have downloaded. If you need to check for missed symbols go to the "downloaded_symbols.csv" file and match it to the entire S&P500 list. Other than the fact that you need a folder named "csv_day_test" in the same folder as the python script, there's not much to using this. It's pretty simple (and shouldn't hang like the GUI version sometimes does).

It's hard coded to do "1 min" bars over the course of "1 D". Change these if you'd like to download other data. You can also add/subtract symbols as you would expect. If you want it to print data it receives into the Python window, you can remove the # mark before the "print msg.reqId, msg.date," ... etc. This will, however, slow things down to some extent.

Here's the code:

 from time import sleep, strftime, localtime  
 from ib.ext.Contract import Contract  
 from ib.opt import ibConnection, message  
 import _mysql  
   
 new_symbolinput = ['MMM','ACE','AES','AFL','GAS','T','ABT','ANF','ACN','ADBE','AMD','AET','A','APD','ARG','AKAM','AA','ALXN','ATI','AGN','ALL','ANR','ALTR','MO','AMZN','AEE','AEP','AXP','AIG','AMT','AMP','ABC','AMGN','APH','APC','ADI','AON','APA','AIV','APOL','AAPL','AMAT','ADM','AIZ','AN','AZO','ADSK','ADP','AVB','AVY','AVP','BBT','BMC','BHI','BLL','BAC','BCR','BAX','BEAM','BDX','BBBY','BMS','BRK B','BBY','BIG','BIIB','BLK','HRB','BA','BWA','BXP','BSX','BMY','BRCM','BF B','CA','CBG','CBS','CF','CHRW','CMS','CNX','CSX','CVS','CVC','COG','CAM','CPB','COF','CAH','CFN','KMX','CCL','CAT','CELG','CNP','CTL','CERN','CHK','CVX','CME','CMG','CB','CI','CINF','CTAS','CSCO','C','CTXS','CLF','CLX','COH','KO','CCE','CTSH','CL','CMCSA','CMA','CSC','CAG','COP','ED','STZ','CBE','GLW','COST','CVH','COV','CCI','CMI','DTV','DTE','DHR','DRI','DVA','DV','DF','DE','DELL','DNR','XRAY','DVN','DO','DFS','DISCA','DLTR','D','RRD','DOV','DOW','DPS','DD','DUK','DNB','ETFC','EMC','EOG','EQT','EMN','ETN','ECL','EIX','EW','EA','EMR','ETR','EFX','EQR','EL','EXC','EXPE','EXPD','ESRX','XOM','FFIV','FLIR','FMC','FTI','FDO','FAST','FDX','FII','FIS','FITB','FHN','FSLR','FE','FISV','FLS','FLR','F','FRX','FOSL','BEN','FCX','FTR','GME','GCI','GPS','GD','GE','GIS','GPC','GNW','GILD','GS','GR','GT','GOOG','GWW','HCP','HAL','HOG','HAR','HRS','HIG','HAS','HCN','HNZ','HP','HSY','HES','HPQ','HD','HON','HRL','DHI','HSP','HST','HCBK','HUM','HBAN','ITW','IR','TEG','INTC','ICE','IPG','IBM','IFF','IGT','IP','INTU','ISRG','IVZ','IRM','JDSU','JPM','JBL','JEC','JNJ','JCI','JOY','JNPR','KLAC','K','KEY','KMB','KIM','KMI','KSS','KFT','KR','LLL','LSI','LH','LRCX','LM','LEG','LEN','LUK','LXK','LIFE','LLY','LTD','LNC','LLTC','LMT','L','LO','LOW','MTB','M','MRO','MPC','MAR','MMC','MAS','MA','MAT','MKC','MCD','MHP','MCK','MJN','MWV','MDT','MRK','MET','PCS','MCHP','MU','MSFT','MOLX','TAP','MON','MCO','MS','MOS','MSI','MUR','MYL','NKE','NRG','NYX','NBR','NDAQ','NOV','NTAP','NFLX','NWL','NFX','NEM','NWSA','NEE','NI','NE','NBL','JWN','NSC','NU','NTRS','NOC','NUE','NVDA','ORLY','OKE','OXY','OMC','ORCL','OI','PCAR','PCG','PNC','PPG','PPL','PLL','PH','PDCO','PAYX','BTU','JCP','PBCT','POM','PEP','PKI','PRGO','PFE','PM','PSX','PNW','PXD','PBI','PCL','PX','PCP','PCLN','PFG','PLD','PG','PGN','PGR','PRU','PEG','PSA','PHM','QEP','QCOM','PWR','DGX','RL','RRC','RTN','RHT','RF','RSG','RAI','RHI','ROK','COL','ROP','ROST','RDC','R','SAI','SCG','SLM','SWY','CRM','SNDK','SLE','SLB','SCHW','SNI','SEE','SHLD','SRE','SHW','SIAL','SPG','SJM','SNA','SO','LUV','SWN','SE','S','STJ','SWK','SPLS','SBUX','HOT','STT','SRCL','SYK','STI','SUN','SYMC','SYY','TROW','TEL','TE','TJX','TGT','THC','TDC','TER','TSO','TXN','TXT','BK','WMB','TMO','TIF','TWC','TWX','TIE','TMK','TSS','TRV','TRIP','TYC','TSN','USB','UNP','UPS','X','UTX','UNH','UNM','URBN','VFC','VLO','VAR','VTR','VRSN','VZ','VIAB','V','VNO','VMC','WPX','WMT','WAG','DIS','WPO','WM','WAT','WPI','WLP','WFC','WDC','WU','WY','WHR','WFM','WIN','WEC','WYN','WYNN','XL','XEL','XRX','XLNX','XYL','YHOO','YUM','ZMH','ZION','EBAY']  
 newDataList = []  
 dataDownload = []  
   
 def historical_data_handler(msg):  
   global newDataList  
   #print msg.reqId, msg.date, msg.open, msg.high, msg.low, msg.close, msg.volume  
   if ('finished' in str(msg.date)) == False:  
     new_symbol = new_symbolinput[msg.reqId]  
     dataStr = '%s, %s, %s, %s, %s, %s, %s' % (new_symbol, strftime("%Y-%m-%d %H:%M:%S", localtime(int(msg.date))), msg.open, msg.high, msg.low, msg.close, msg.volume)  
     newDataList = newDataList + [dataStr]  
   else:  
     new_symbol = new_symbolinput[msg.reqId]  
     filename = 'minutetrades' + new_symbol + '.csv'  
     csvfile = open('csv_day_test/' + filename,'wb')  
     for item in newDataList:  
       csvfile.write('%s \n' % item)  
     csvfile.close()  
     newDataList = []  
     global dataDownload  
     dataDownload.append(new_symbol)  
   
 con = ibConnection()  
 con.register(historical_data_handler, message.HistoricalData)  
 con.connect()  
   
 symbol_id = 0  
 for i in new_symbolinput:  
   print i  
   qqq = Contract()  
   qqq.m_symbol = i  
   qqq.m_secType = 'STK'  
   qqq.m_exchange = 'SMART'  
   qqq.m_currency = 'USD'  
   con.reqHistoricalData(symbol_id, qqq, '', '1 D', '1 min', 'TRADES', 1, 2)  
   
   symbol_id = symbol_id + 1  
   sleep(10)  
   
 print dataDownload  
 filename = 'downloaded_symbols.csv'  
 csvfile = open('csv_day_test/' + filename,'wb')  
 for item in dataDownload:  
   csvfile.write('%s \n' % item)  
 csvfile.close()  

Note: Downloads everything except SLE and PGN. Might not be symbols on the S&P500; haven't checked yet...

Amazon's Hardware

This article doesn't seem, to me, to give any insight into Amazon's desire to stay in hardware, mostly through Kindle. With a comment like the following:

"I have said this many times, but I believe the Internet is the platform of the future."

I am losing more and more (undeserved) faith in the media industry to provide interesting, informative, insightful, and thought-provoking pieces. 

You believe the Internet is the platform of the future? Well, you must be a fucking visionary.

Monday, July 23, 2012

Some Comments

The Epicurean Dealmaker has to be one of my favorite bloggers and, recently, he has hit 1M unique views. If you have yet to enjoy his writing, I suggest you check him out.

And, this has to be one of the worst articles I have read on "VIX trading". Maybe it's just because I have a friend whose work at a hedge fund deals almost entirely with the VIX. Or maybe it's because I am in a critical mood.

Probably both.

IB Historical Quotes Downloader

Slowly getting to where I want it to be. Here's a workable version that downloads quotes (you can insert multiple tickers with commas separating them--no spaces after the commas) to csv files and stores them in a subdirectory "csv_day". The MySQL part shouldn't be difficult. But I'm working on dealing with IB's quote download limits and some python inefficiency.

Here's the current code:

 from time import sleep, strftime, localtime  
 from ib.ext.Contract import Contract  
 from ib.opt import ibConnection, message  
 from Tkinter import *  
 import _mysql  
 import string  
   
 class App:  
   
   def __init__(self, master):  
   
     #list to keep data series, list for multiple symbols, j to keep track of current symbol  
     self.newDataList = []  
     self.new_symbolinput = []  
     self.j=0  
   
     #connect here to prevent double connections later on...  
     self.con = ibConnection()  
     self.con.register(self.historical_data_handler, message.HistoricalData)  
     self.con.connect()  
   
     #begin gui (labels should make it fairly self-explanatory)  
     frame = Frame(master)  
     frame.pack()  
   
     self.mysqlinfo_label = Label(frame, text='MySQL fields:')  
     self.mysqlinfo_label.grid(row=0)  
   
     self.label_host = Label(frame, text='Host:')  
     self.label_host.grid(row=1)  
   
     host_text = StringVar()  
     host_text.set("127.0.0.1")  
   
     self.entry_host = Entry(frame, textvariable=host_text)  
     self.entry_host.grid(row=1, column=1)  
   
     self.label_user = Label(frame, text='User:')  
     self.label_user.grid(row=2)  
   
     user_text = StringVar()  
     user_text.set("root")  
   
     self.entry_user = Entry(frame, textvariable=user_text)  
     self.entry_user.grid(row=2, column=1)  
   
     self.label_password = Label(frame, text='Password:')  
     self.label_password.grid(row=3)  
   
     self.entry_password = Entry(frame, show="*")  
     self.entry_password.grid(row=3, column=1)  
   
     self.label_database = Label(frame, text='Database:')  
     self.label_database.grid(row=4)  
   
     database_text = StringVar()  
     database_text.set("stocks")  
   
     self.entry_database = Entry(frame, textvariable=database_text)  
     self.entry_database.grid(row=4, column=1)  
   
     self.label_empty = Label(frame, text='')  
     self.label_empty.grid(row=5)   
   
     self.label_twsfields = Label(frame, text='TWS fields:')  
     self.label_twsfields.grid(row=6)  
   
     self.label_server = Label(frame, text='Server:')  
     self.label_server.grid(row=7)  
   
     twsserver_text = StringVar()  
     twsserver_text.set("127.0.0.1")  
   
     self.entry_server = Entry(frame, textvariable=twsserver_text)  
     self.entry_server.grid(row=7, column=1)  
   
     self.label_empty = Label(frame, text='')  
     self.label_empty.grid(row=8)   
   
     self.label_twscontractinfo = Label(frame, text='TWS contract info:')  
     self.label_twscontractinfo.grid(row=9)  
   
     self.label_symbol = Label(frame, text='Symbol:')  
     self.label_symbol.grid(row=10)  
   
     self.entry_symbol = Entry(frame)  
     self.entry_symbol.grid(row=10, column=1)  
   
     self.label_barsize = Label(frame, text='Bar Size:')  
     self.label_barsize.grid(row=11)  
   
     self.barsize_selected = StringVar(frame)  
     self.barsize_selected.set("1 min")  
   
     self.optionmenu_barsize = OptionMenu(frame, self.barsize_selected, "30 secs", "1 min", "5 mins", "10 mins", "15 mins", "1 hour", "4 hours", "1 day")  
     self.optionmenu_barsize.grid(row=11, column=1)  
   
     self.label_duration = Label(frame, text='Duration:')  
     self.label_duration.grid(row=12)  
   
     self.duration_selected = StringVar(frame)  
     self.duration_selected.set("1 W")  
   
     self.optionmenu_duration = OptionMenu(frame, self.duration_selected, "1 H", "4 H", "1 D", "1 W", "1 M", "1 Y")  
     self.optionmenu_duration.grid(row=12, column=1)  
       
   
     self.label_empty = Label(frame, text='')  
     self.label_empty.grid(row=13)      
   
     self.button_download = Button(frame, text="Download", command=self.tws_connect)  
     self.button_download.grid(row=14, column=1)  
   
     self.button_import = Button(frame, text="Import", command=self.mysql_connect)  
     self.button_import.grid(row=15, column=1)  
   
     self.label_empty = Label(frame, text='')  
     self.label_empty.grid(row=16)   
   
   #function for sending historical data requests  
   def tws_connect(self):  
     print "connecting to tws..."  
     print "tws server: " + self.entry_server.get()  
   
     self.new_symbolinput = string.split(self.entry_symbol.get(), ',')  
   
     print self.new_symbolinput  
   
     #run through all symbols, requesting historical data  
     self.symbol_id = 0  
     for i in self.new_symbolinput:  
       print i  
       qqq = Contract()  
       qqq.m_symbol = i  
       qqq.m_secType = 'STK'  
       qqq.m_exchange = 'SMART'  
       qqq.m_currency = 'USD'  
       endtime = strftime('%Y%m%d %H:%M:%S')  
       durationreq = '%s' % self.duration_selected.get()  
       barsizereq = '%s' % self.barsize_selected.get()  
       self.con.reqHistoricalData(self.symbol_id, qqq, '', durationreq, barsizereq, 'TRADES', 1, 2)  
       self.symbol_id = self.symbol_id + 1  
   
       #if doing more than 60 symbols, this is a simple way to avoid IB's 60symbol/10min limit...  
         
   #function for putting data into csv file and, eventually, into mysql database  
   def mysql_connect(self):  
       
     print "MySQL host: " + self.entry_host.get()  
     print "MySQL user: " + self.entry_user.get()  
     print "MySQL database: " + self.entry_database.get()  
   
   #required for IB API  
   def historical_data_handler(self, msg):  
     print msg.reqId, msg.date, msg.open, msg.high, msg.low, msg.close, msg.volume  
   
     #don't add 'finished...' statement to data list  
     if ('finished' in str(msg.date)) == False:  
       new_symbol = self.new_symbolinput[msg.reqId]  
       dataStr = '%s, %s, %s, %s, %s, %s, %s' % (new_symbol, strftime("%Y-%m-%d %H:%M:%S", localtime(int(msg.date))), msg.open, msg.high, msg.low, msg.close, msg.volume)  
       self.newDataList.append(dataStr)  
     #if 'finished...' appears jump to next symbol (THIS IS BROKEN because IB doesn't necessarily send requests back to you in the order sent to them...)  
     else:  
       new_symbol = self.new_symbolinput[msg.reqId]  
       filename = 'minutetrades' + new_symbol + '.csv'  
       csvfile = open('csv_day/' + filename,'wb')  
       for item in self.newDataList:  
         csvfile.write('%s \n' % item)  
       csvfile.close()  
       self.newDataList = []  
   
 root = Tk()  
 root.title('Historical Data: Download and Import')  
 app = App(root)  
   
 #run gui  
 root.mainloop()  

Saturday, July 21, 2012

Multiple Tickers on IB

I believe I've fixed the problem accessing multiple tickers under my Python IB historical data extractor. Instead of hoping IB will send me the data in the order I sent IB the data, I match the initial tickerId I send IB with the msg.reqId I receive back. All tickers get aligned correctly and if you happen to input an invalid ticker or IB decides not to send you a ticker, it doesn't get matched up to some other ticker's data (you just don't get it in the output file).

I'll post the code shortly...I'd like to get the MySQL part done too.

Friday, July 20, 2012

Super-Size Me?

I skimmed this article earlier today. It's about the growing size of phones. I, instead, think of it more as the shrinking of the computer with the addition of phone capabilities. Perhaps others dislike the size of their phone, but I am much happier with my Samsung Charge than with anything I've had before...and I wouldn't mind an upgrade.

Thursday, July 19, 2012

Apple, Bellagio Comparison

This is an interesting article about why Apple will continue winning. However, I think he cuts his analogy slightly short. With Steve Jobs gone, what is going to drive Apple to uphold its amazing service and continue growing its loyal customer base? Stock holders? I don't think so.

Why Scott Bell doesn't make the connection between the absence of Wynn at the Bellagio and the absence of Jobs (much more recent) at Apple, beats the hell out of me. It's not mentioned. I wouldn't be surprised if someone at Apple started to cut corners.

And, I wouldn't be surprised if the fervent loyalty begins to die off (perhaps slowly) now that Apple's religious leader is dead.

Wednesday, July 18, 2012

People You Need

I'm a tad surprised that Abnormal Returns didn't post a link to this article about the people who you need in "your corner." It's simple. It's good. So many people tend to forget that to grow as an individual you need others. /steps off soap box.

Tuesday, July 17, 2012

Download Historical Data From Interactive Brokers

If you enjoy the following, consider signing up for the Gödel's Market Newsletter.

It's not quite done. I haven't worked out the kinks with downloading multiple symbols at a time (sometimes it works, sometimes it doesn't download one and the symbol names in the csv file get screwed up...). Also, it doesn't connect and import the created csv file into your MySQL database. That shouldn't be too big of a step, especially since it's already programmed for the Yahoo! Importer. Working out the other kink will take more time.

Again, you need certain modules imported. Python-MySQL and IbPy, being the most important.

Here's alpha code v0.01:

 from time import sleep, strftime, localtime  
 from ib.ext.Contract import Contract  
 from ib.opt import ibConnection, message  
 from Tkinter import *  
 import _mysql  
 import csv  
 import string  
   
   
 class App:  
   
   def __init__(self, master):  
   
     self.newDataList = []  
     self.new_symbolinput = []  
     self.j=0  
   
     #connect here to prevent double connections later on...  
     self.con = ibConnection()  
     self.con.register(self.historical_data_handler, message.HistoricalData)  
     self.con.connect()  
   
     frame = Frame(master)  
     frame.pack()  
   
     self.mysqlinfo_label = Label(frame, text='MySQL fields:')  
     self.mysqlinfo_label.grid(row=0)  
   
     self.label_host = Label(frame, text='Host:')  
     self.label_host.grid(row=1)  
   
     host_text = StringVar()  
     host_text.set("127.0.0.1")  
   
     self.entry_host = Entry(frame, textvariable=host_text)  
     self.entry_host.grid(row=1, column=1)  
   
     self.label_user = Label(frame, text='User:')  
     self.label_user.grid(row=2)  
   
     user_text = StringVar()  
     user_text.set("root")  
   
     self.entry_user = Entry(frame, textvariable=user_text)  
     self.entry_user.grid(row=2, column=1)  
   
     self.label_password = Label(frame, text='Password:')  
     self.label_password.grid(row=3)  
   
     self.entry_password = Entry(frame, show="*")  
     self.entry_password.grid(row=3, column=1)  
   
     self.label_database = Label(frame, text='Database:')  
     self.label_database.grid(row=4)  
   
     database_text = StringVar()  
     database_text.set("stocks")  
   
     self.entry_database = Entry(frame, textvariable=database_text)  
     self.entry_database.grid(row=4, column=1)  
   
     self.label_empty = Label(frame, text='')  
     self.label_empty.grid(row=5)   
   
     self.label_twsfields = Label(frame, text='TWS fields:')  
     self.label_twsfields.grid(row=6)  
   
     self.label_server = Label(frame, text='Server:')  
     self.label_server.grid(row=7)  
   
     twsserver_text = StringVar()  
     twsserver_text.set("127.0.0.1")  
   
     self.entry_server = Entry(frame, textvariable=twsserver_text)  
     self.entry_server.grid(row=7, column=1)  
   
     self.label_empty = Label(frame, text='')  
     self.label_empty.grid(row=8)   
   
     self.label_twscontractinfo = Label(frame, text='TWS contract info:')  
     self.label_twscontractinfo.grid(row=9)  
   
     self.label_symbol = Label(frame, text='Symbol:')  
     self.label_symbol.grid(row=10)  
   
     self.entry_symbol = Entry(frame)  
     self.entry_symbol.grid(row=10, column=1)  
   
     self.label_barsize = Label(frame, text='Bar Size:')  
     self.label_barsize.grid(row=11)  
   
     self.barsize_selected = StringVar(frame)  
     self.barsize_selected.set("1 min")  
   
     self.optionmenu_barsize = OptionMenu(frame, self.barsize_selected, "30 secs", "1 min", "5 mins", "10 mins", "15 mins", "1 hour", "4 hours", "1 day")  
     self.optionmenu_barsize.grid(row=11, column=1)  
   
     self.label_duration = Label(frame, text='Duration:')  
     self.label_duration.grid(row=12)  
   
     self.duration_selected = StringVar(frame)  
     self.duration_selected.set("1 W")  
   
     self.optionmenu_duration = OptionMenu(frame, self.duration_selected, "1 H", "4 H", "1 D", "1 W", "1 M", "1 Y")  
     self.optionmenu_duration.grid(row=12, column=1)  
       
   
     self.label_empty = Label(frame, text='')  
     self.label_empty.grid(row=13)      
   
     self.button_download = Button(frame, text="Download", command=self.tws_connect)  
     self.button_download.grid(row=14, column=1)  
   
     self.button_import = Button(frame, text="Import", command=self.mysql_connect)  
     self.button_import.grid(row=15, column=1)  
   
     self.label_empty = Label(frame, text='')  
     self.label_empty.grid(row=16)   
   
   def say_hi(self):  
     print "loading data..."  
   
   def tws_connect(self):  
     print "connecting to tws..."  
     print "tws server: " + self.entry_server.get()  
   
     self.new_symbolinput = string.split(self.entry_symbol.get(), ',')  
   
     #print raw_symbol_input  
     print self.new_symbolinput  
   
     print self.j  
   
     for i in self.new_symbolinput:  
       print i  
       qqq = Contract()  
       qqq.m_symbol = i  
       qqq.m_secType = 'STK'  
       qqq.m_exchange = 'SMART'  
       qqq.m_currency = 'USD'  
       endtime = strftime('%Y%m%d %H:%M:%S')  
       durationreq = '%s' % self.duration_selected.get()  
       barsizereq = '%s' % self.barsize_selected.get()  
       self.con.reqHistoricalData(0, qqq, '', durationreq, barsizereq, 'TRADES', 1, 2)  
   
   def mysql_connect(self):  
   
     #write newDataList to csv file  
     csvfile = open('minutetrades2.csv','wb')  
     for item in self.newDataList:  
       csvfile.write('%s \n' % item)  
   
     csvfile.close()  
   
     print "Printing dataList..."  
     print self.newDataList  
     print "connecting to mysql..."  
       
     print "MySQL host: " + self.entry_host.get()  
     print "MySQL user: " + self.entry_user.get()  
     print "MySQL database: " + self.entry_database.get()  
   
     self.contract_info()  
   
   def contract_info(self):  
     print "contract info..."  
     print "Symbol: " + self.entry_symbol.get()  
     print "Bar size: " + self.barsize_selected.get()  
   
   def historical_data_handler(self, msg):  
     print msg.date, msg.open, msg.high, msg.low, msg.close, msg.volume  
     if ('finished' in str(msg.date)) == False:  
       new_symbol = self.new_symbolinput[self.j]  
       dataStr = '%s, %s, %s, %s, %s, %s, %s' % (new_symbol, strftime("%Y-%m-%d %H:%M:%S", localtime(int(msg.date))), msg.open, msg.high, msg.low, msg.close, msg.volume)  
       #prevent addition of 'finished...' statement to newDataList  
       self.newDataList.append(dataStr)  
     else:  
       self.j = (self.j)+1  
       print self.j  
   
 root = Tk()  
 root.title('Historical Data: Download and Import')  
 app = App(root)  
   
 root.mainloop()  

(If you've enjoyed this article, consider signing up for the Gödel's Market Newsletter.)

Sunday, July 15, 2012

Synergy

For traders, quants, or anyone who wants to use multiple computers and screens under a single keyboard/mouse combo, check out Synergy. The software works really well, and it's free. Currently I have it  in use across two computers and three monitors.

MATLAB Built-in Financial Functions

I wrote a Black-Scholes option price calculator function in MATLAB and was working on an implied volatility calculator when I came across some built-in MATLAB functions such as blsprice (Black-Scholes price) and blsimpv (to calculate implied volatility using the Black-Scholes equation).

Pretty cool. I'm sure there are countless others as well...

Put-Call Parity Calculator

If you enjoy the following, consider signing up for the Gödel's Market Newsletter.

I've been reading "Numerical Methods in Finance and Economics, A MATLAB Based Introduction 2nd Edition". They obviously go into put-call parity early on. It's an extremely fascinating concept that given the risk free interest rate (r), the distance until expiration (t), the initial stock price (s), and the strike price (k), that you can then solve for the price of the call (c) given you have the price of the put (p) or vice versa.

No arbitrage financial pricing is extremely interesting (and practical). Here's a MATLAB script I wrote that you can use to look for "arbitrage" opportunity in the put-call parity sense. It'll ask you for several inputs (r,t,s,k,c,p) and tell you what the "call side value" (c + k*e(-r*t)) is and what the "put side value" (p + s) is. You can then compare.

(Example with current SPY options; first part is entry, second is output:)



 % arbitrage; put-call parity checker  
   
 %risk free interest rate  
 r = input('What is the risk free rate? ');  
   
 %time period  
 t = input('How long until expiration? ');  
   
 %stock price, initially  
 s = input('What is the initial stock price? ');  
   
 %strike price  
 k = input('What is the strike price? ');  
   
 %grab call price  
 c = input('What is the call price? ');  
   
 %grab put price  
 p = input('What is the put price? ');  
   
 fprintf('Risk free rate: %d \n', r);  
 fprintf('Time period: %d \n', t);  
 fprintf('Initial stock value: %d \n', s);  
 fprintf('Strike price: %d \n', k);  
 fprintf('Call price: %d \n', c);  
 fprintf('Put price: %d \n', p);  
   
 call_side_value = c + k*exp(-r*t)  
 put_side_value = p + s  

(Edit: fixed an error in call_side_value calculation. Should be good to go.)

(If you've enjoyed this article, consider signing up for the Gödel's Market Newsletter.)

Wednesday, July 11, 2012

Matlab Stock Correlation Matrix

If you enjoy the following, consider signing up for the Gödel's Market Newsletter.

So, maybe you used the Python Yahoo! data importer script I posted; or, maybe, you have your own price data. And, perhaps you want to run a script to see what the correlation is among the stocks in your database. This code will do just that.

You need to download the MySQL JDBC connector and go through the hassle of adding the .jar file to your Matlab java path. It's worth the struggle, though.

Here's the code with some comments to hopefully help you along (and remind me what I did later):

   
 %test variables to limit matrix sizes...  
 num_stocks = 500;  
 num_close_values = 20;  
 num_log_values = 19;  
   
 %connect to the database  
 conn = database('stocks','root','*****','com.mysql.jdbc.Driver','jdbc:mysql://localhost:3306/stocks');  
   
 %query the symbols in the database  
 str_query_symbols = 'SELECT distinct symbol FROM stock_prices_day';  
 symbol_cell = fetch(conn, str_query_symbols);  
   
 %create matrices to prevent matrix resizing when inserting cell values..  
 mat_log_change = zeros(num_log_values,num_stocks);  
 mat_values_adj_close = zeros(num_close_values,num_stocks);  
   
 %grab adj_close info for a each symbol; then cell2mat it into a larger  
 %matrix  
 for i = 1:num_stocks  
   symbol = cell2mat(symbol_cell(i));  
   str_query_adj_close = ['SELECT adj_close FROM stock_prices_day WHERE symbol = ''' symbol ''' and date > ''2012-06-01'''];  
   mat_values_adj_close(:,i) = cell2mat(fetch(conn, str_query_adj_close));  
     
   %use this to calculate natrual log changes as you move along  
   for j = 1: num_log_values  
     %mat_values_adj_close(j,i)  
     mat_log_change(j,i) = log((mat_values_adj_close(j,i))/(mat_values_adj_close((j+1),i)));  
   end  
 end  
   
 %next calculate correlation coefficients among the various columns  
 mat_correlations = zeros(num_stocks,num_stocks);  
 for i = 1:num_stocks  
   for j = 1:num_stocks  
     A = mat_log_change(:,i);  
     B = mat_log_change(:,j);  
     R = corrcoef(A,B);  
     mat_correlations(i,j) = R(2);  
   end  
 end  
   
 mat_correlations  

(If you've enjoyed this article, consider signing up for the Gödel's Market Newsletter.)

Correlation Correlations

I really like this article linked by Abnormal Returns. Look at the relatively close correlation of the S&P 500 and Euro 350. And then look at the returns.

Tuesday, July 10, 2012

Simple Version of Yahoo! MySQL Importer

If you enjoy the following, consider signing up for the Gödel's Market Newsletter.

I decided to post the source code for my Yahoo! Stock Quote MySQL Importer Python script.

This is the simple version without the ability to add multiple stock tickers at once and no choice of time limits. Also, it doesn't download economic info or keep track of dividends.

In order to use this, you must have Python 2.7 (or something that can run the code equivalently; I don't think Python 3+ works), the Python-MySQL (MySQLdb) module, and MySQL installed (I'm using server 5.5).

Within your MySQL server you must have a "schema" (or "database") called "stocks". Actually, you can call it whatever you want, because you have the option to change the name in the Python program. But, it is preselected for "stocks".

Within this "schema"/"database" you must have a table called "stock_prices_day". This is hardcoded, but can obviously be changed if you know a little python, or just read through the code and look for any instance of "stock_prices_day" and replace them with whatever you want your table to be called.

Within "stock_prices_day" you must have the following columns with the indicated data types: "symbol" varchar(5), "date" date, "open" decimal(5,3), "high" decimal(5,3), "low" decimal(5,3), "close" decimal(5,3), "volume" int, "adj_close" decimal(5,3).

When you have all of that, you can run the following code, insert your server information (ip, username, password, etc) and the symbol you want to insert. It'll download it and insert the symbol into the database.

BAM! you're on your way to a real hedge fund-esque setup. :D (well, almost).

Rules on the code:
1) Only for personal use by investors with less than $100k in liquid assets (not for use by businesses, corporations, etc).
2) Not for resale and reuse requires my consent.
3) Post a comment if you'd like access to a more complete version (date selection, multiple symbols, etc).


 from time import sleep, strftime, localtime  
 from Tkinter import *  
 import MySQLdb  
 import urllib  
 import csv  
 import os  
   
 class App:  
   
   def __init__(self, master):  
   
     frame = Frame(master)  
     frame.pack()  
   
     self.mysqlinfo_label = Label(frame, text='MySQL fields:')  
     self.mysqlinfo_label.grid(row=0)  
   
     self.label_host = Label(frame, text='Host:')  
     self.label_host.grid(row=1)  
   
     host_text = StringVar()  
     host_text.set("127.0.0.1")  
   
     self.entry_host = Entry(frame, textvariable=host_text)  
     self.entry_host.grid(row=1, column=1)  
   
     self.label_user = Label(frame, text='User:')  
     self.label_user.grid(row=2)  
   
     user_text = StringVar()  
     user_text.set("root")  
   
     self.entry_user = Entry(frame, textvariable=user_text)  
     self.entry_user.grid(row=2, column=1)  
   
     self.label_password = Label(frame, text='Password:')  
     self.label_password.grid(row=3)  
   
     self.entry_password = Entry(frame, show="*")  
     self.entry_password.grid(row=3, column=1)  
   
     self.label_database = Label(frame, text='Database:')  
     self.label_database.grid(row=4)  
   
     database_text = StringVar()  
     database_text.set("stocks")  
   
     self.entry_database = Entry(frame, textvariable=database_text)  
     self.entry_database.grid(row=4, column=1)  
   
     self.label_empty = Label(frame, text='')  
     self.label_empty.grid(row=5)   
   
     self.label_twscontractinfo = Label(frame, text='Yahoo info:')  
     self.label_twscontractinfo.grid(row=9)  
   
     self.label_symbol = Label(frame, text='Symbol:')  
     self.label_symbol.grid(row=10)  
   
     self.entry_symbol = Entry(frame)  
     self.entry_symbol.grid(row=10, column=1)  
       
   
     self.label_empty = Label(frame, text='')  
     self.label_empty.grid(row=13)      
   
     self.button_download = Button(frame, text="Download", command=self.tws_connect)  
     self.button_download.grid(row=14, column=1)  
   
     self.button_import = Button(frame, text="Import", command=self.mysql_connect)  
     self.button_import.grid(row=15, column=1)  
   
     self.label_empty = Label(frame, text='')  
     self.label_empty.grid(row=16)   
   
   
   def tws_connect(self):  
     print "downloading csv file from yahoo..."  
     webFile = urllib.urlopen("http://ichart.finance.yahoo.com/table.csv?s=" + self.entry_symbol.get())  
     fileName = self.entry_symbol.get() + ".csv"  
     localFile = open(fileName.split('/')[-1], 'w')  
     localFile.write(webFile.read())  
     webFile.close()  
     localFile.close()  
   
     fieldnames = ['Symbol', 'Date', 'Open', 'High', 'Low', 'Close', 'Volume', 'Adj Close']  
     fileName2 = self.entry_symbol.get() + "2.csv"  
     with open(fileName, 'rb') as csvinput:  
       with open(fileName2, 'wb') as csvoutput:  
         csvwriter = csv.DictWriter(csvoutput, fieldnames, delimiter=',')  
         csvwriter.writeheader()  
         for row in csv.DictReader(csvinput):  
           row['Symbol'] = self.entry_symbol.get()  
           csvwriter.writerow(row)  
   
   
   def mysql_connect(self):  
     print "connecting to mysql..."  
       
     print "MySQL host: " + self.entry_host.get()  
     print "MySQL user: " + self.entry_user.get()  
     print "MySQL database: " + self.entry_database.get()  
   
     db = MySQLdb.connect(host=self.entry_host.get(), user=self.entry_user.get(),passwd=self.entry_password.get(), db=self.entry_database.get())  
     cur = db.cursor()  
   
     current_path = os.path()  
   
     print current_path  
   
     cur.execute("load data local infile '" + current_path + self.entry_symbol.get() + "2.csv' into table `stocks`.`stock_prices_day` fields terminated by ',' lines terminated by '\n' ignore 1 lines (`symbol`,`date`,`open`,`high`,`low`,`close`,`volume`,`adj_close`);")  
     db.commit()  
     self.contract_info()  
   
   def contract_info(self):  
     print "contract info..."  
     print "Symbol: " + self.entry_symbol.get()  
   
 root = Tk()  
 root.title('Historical Data: Download and Import')  
 app = App(root)  
   
 root.mainloop()  


(If you've enjoyed this, consider signing up for the Gödel's Market Newsletter.)

Monday, July 9, 2012

Those Who Finish Second

Here's a really good article. Yeah, it may not always be true that those who finish first were mostly lucky or bold; but, it can certainly be the case. Think Warren Buffet, Bill Gates, or Mark Zuckerberg. They're all intelligent, skillful, and successful. But do you do yourself a favor following their strategies? Probably not.

Poker Notes

Bovada.lv deposited a free $20 in my account. I haven't played for quite some time, but I'm up to >$170 (playing $25 buyin .10/.25). Here are a few notes on the game of poker that have crossed my mind:


-create a model of other players' hands

-determine best bet to further refine player hands

-use further betting to extract as much value based on others' hand

-all while keeping your hand in mind
although no need for it to win, if strategy typically
leads to others folding

-keep appearances in mind (not too much raising, folding, etc)

-always try to play with the 'soft'
why make your life harder than it has to be?

I think something similar can be used for trading.

Sunday, July 8, 2012

Yahoo!

So, I still haven't gotten around to packing everything into a self-installing exe. I've been extremely busy with job interviews, sharpening my programming skills, and hanging out with friends before I most likely move some 400 miles away.

I have been able to use the MySQL server I setup on a new very inexpensive server. I've downloaded Yahoo! data on the companies currently on the S&P500 and have ran several back tests with one of Charles D. Kirkpatrick's books in mind. I don't have any definitive results yet. But it looks promising.

I'm thinking of rewriting the Yahoo! program in Java for easier distribution. Or maybe C/C++. I don't know. I know I'm not ready to release it open source.

More soon.