Archive for March, 2009

Thinkscript Tip: GetAggregationPeriod

March 25, 2009

In Thinkscript, there is a function called GetAggregationPeriod(). This function returns the current aggregation period in milliseconds. The aggregation period is defined as the number of milliseconds it takes to complete a candle on the current chart timeframe. Here are the aggregation period values for the different ToS chart timeframes:

Any Tick Chart = 0
1 min = 60,000
2 min = 120,000
3 min = 180,000
4 min = 240,000
5 min = 300,000
10 min = 600,000
15 min = 900,000
20 min = 1,200,000
30 min = 1,800,000
1 hr = 3,600,000
2 hr = 7,200,000
4 hr = 14,400,000
Daily = 86,400,000
Weekly = 604,800,000
Monthly = 2,592,000,000

There are a few built in constants for some of these aggregation periods, such as Aggregationperiod.MIN and Aggregationperiod.DAY. These constants would return the values for 1 min and Daily from the list above. But as you can see, there are many available values, more than there are defined constants.

If you want to tell the difference between intraday and end of day charts, you simply check if the GetAggregationPeriod() function returns a value of 86,400,000 or more. If so, it’s daily or greater. Less than that, it’s an intraday chart. You can also use it in any script that needs to know the duration of a candle. Just call the function and divide the answer by 60,000 to get the number of minutes, or divide by 1,000 to get the number of seconds.

In my earlier usage of GetAggregationPeriod in strategies, I used it incorrectly to try to indentify the differences in intraday and end of day charts. I was trapping specific values of aggregation period instead of just checking for daily or above. My check for the market close was also messed up; it only worked right if you showed aftermarket data. I will be updating all of my strategy codes over time to calculate these the correct way.

The following code will get the aggregation period, and check if that value is equal to or greater than the value for a daily candle. If it is, then the market is always considered to be “open” as far as the study/strategy is concerned. If the aggregation period value is less than the value for a daily candle, then we know we are on an intraday chart and the check is made to see if the market is open or not:

input opentime=0930;
input closetime=1600;
def AP=getaggregationperiod();
def daily=if AP>=aggregationPeriod.DAY then 1 else 0;
def isopen=if daily then 1 else if secondsFromTime(opentime)>=0 and secondstillTime(closetime)>=0 then 1 else 0;

Then you can use isopen as a boolean to check if the market is open before entering a strategy trade.

The next code will use aggregation period to check if we are on the last candle of the market session, which is useful for an “exit at close” strategy:

input closetime=1600;
def AP=getaggregationperiod();
def daily=if AP>=aggregationPeriod.DAY then 1 else 0;
def islastcandle=if daily then 0 else if secondstillTime(closetime)<=AP/1000 then 1 else 0;
addorder(islastcandle,close);

Note that this doesn’t really work for tick charts, where the candle is not time-based. If you do testing with tick charts, I recommend showing all data, not just market hours. If I figure out a better way, I’ll post it.

It’s Here: Short Interest Data Tool

March 24, 2009

Here’s my tool to download the Short Interest data from Yahoo for multiple stock symbols:

Download Here

It’s pre-loaded with the most recent S&P500 stocks and data (as of Sep 8, 2009). You’ll need to enable macros to use the tool. The macro takes about 2 seconds per ticker to run, so the S&P 500 takes about 17 minutes.

This is “Panhandle-ware”: If you feel it’s valuable, hit the donate button and pay what you think it’s worth.

Short Interest Tool Update

March 23, 2009

I’m testing the short interest tool right now. If it works as expected, I’ll put it up tomorrow.

UPDATE: Looks like it’s working! I have a list of 5000 listed stocks. The macro pulls down data for these at roughly one ticker every two seconds, so the whole thing takes just under 3 hours (!!) to run. Luckily, the short interest data is only updated monthly.

I had to perform some trickery to deal with Yahoo’s HTML tables. The Excel file uses a web query to import the data. Depending on which ads get rendered on the page, the specific table numbers change. So I had to import the whole page and then use a Match() function to find the data section with the short interest. If you care about the details, post a comment.

I’ll upload the file tomorrow morning. Donations gladly accepted, though not required. Pay what you think the tool is worth to you!

Reader Request: Multiple Moving Averages Strategy

March 17, 2009

Reader Scott asked for a strategy where the long entry is a close above each of three moving averages, and the exit is the first close below any of them. I’m away from a pc now, so this is all off the top of my head, done on my iPhone. Let me know if there are errors! I’ll be able to fully check this out on Friday.

First, the Long Entry:

# 3 EMA Long Entry
# By Prospectus @ https://readtheprospectus.wordpress.com
#
# Input Declarations:
#
declare LONG_ENTRY;
input opentime=0930;
input closetime=1600;
input EMA_1=50;
input EMA_2=100;
input EMA_3=200;
#
# If intraday, only enter during market hours:
# Note: Tick charts return Aggregation Period = 0
#
def AP=getaggregationperiod();
def daily=if AP>=aggregationPeriod.DAY then 1 else 0;
def isopen=if daily then 1 else if secondsFromTime(opentime)>=0 and secondstillTime(closetime)>=0 then 1 else 0;
#
# Define the entry trigger:
# In this example, we are using a close above
# each of 3 EMA’s:
#
def signal = if close>expaverage(close,EMA_1) AND close>expaverage(close,EMA_2) AND close>expaverage(close,EMA_3) then 1 else 0;
#
# If market open and close above EMA’s then enter on bar close:
#
def trigger=if isopen and signal then 1 else 0;
def orderprice=close;
#
# This code triggers the strategy on the chart.
# Arg. 1 adds order if true, nothing if false
# Arg. 2 is the entry price
#
addorder(trigger,orderprice);
#
# Formatting:
#
setcolor(color.green);

Now, the Long Exit:

# 3 EMA Long Exit
# By Prospectus @ https://readtheprospectus.wordpress.com
#
# Input Declarations:
#
declare LONG_EXIT;
input closetime=1600;
input EMA_1=50;
input EMA_2=100;
input EMA_3=200;
#
# Always exit at close:
#
def AP=getaggregationperiod();
def daily=if AP>=aggregationPeriod.DAY then 1 else 0;
def islastcandle=if daily then 0 else if secondstillTime(closetime)<=AP/1000 then 1 else 0;
#
# Define the exit trigger:
# In this example, we are using a close below any of the EMA’s:
#
def signal = if close<expaverage(close,EMA_1) OR close<expaverage(close,EMA_2) OR close<expaverage(close,EMA_3) then 1 else 0;
#
# If market is closing OR close under any EMA’s then exit on bar close:
#
def trigger=if islastcandle OR signal then 1 else 0;
def orderprice=close;
#
# This code triggers the strategy on the chart.
# Arg. 1 adds order if true, nothing if false
# Arg. 2 is the entry price
#
addorder(trigger,orderprice);
#
# Formatting:
#
setcolor(color.gray);

You should be able to make the short side strategies by simply reversing the > and < signs in the “signal” definitions above, along with changing the “LONG_ENTRY” and “LONG_EXIT” declarations to “SHORT_ENTRY” and “SHORT_EXIT”, respectively.

Let me know if it works!

Updated Strategy Tutorial: Now Works On Daily

March 16, 2009

I added some wizardry with the “getaggregationperiod” function to decide if a chart is intraday or otherwise. Now my EMA Crossover strategy scripts work on all chart timeframes. See the original post for the code.