Created
January 14, 2015 20:52
-
-
Save philomates/2cf9ae2944d90e8049f7 to your computer and use it in GitHub Desktop.
Exploring some simple time-series questions
This file contains hidden or 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
#!/bin/ipython3 | |
""" | |
Exploring some simple time-series questions | |
Phillip Mates | |
Jan 14th, 2015 | |
""" | |
import math | |
LOGGING = False | |
TESTING = True | |
INTERACTIVE_SHELL = False | |
# ############################################# | |
# Some simple utils written ahead of time | |
# ############################################# | |
def log(message): | |
""" simple logging. | |
Prints message if logging flag set | |
Args: | |
message: String | |
Returns: | |
Unit, with IO side-effects | |
""" | |
if LOGGING: | |
print(message) | |
def test(name, test_condition): | |
""" simple testing. | |
Runs test if testing flag is set. | |
Args: | |
name: String naming the test | |
test_condition: Boolean representing success of test | |
Returns: | |
Unit, with IO side-effects | |
""" | |
if TESTING: | |
if test_condition: | |
print("TEST PASSED:", name) | |
else: | |
print("TEST FAILED:", name) | |
# ############################################# | |
# Data processing and Questions | |
# ############################################# | |
def generate_data_point(t): | |
""" Generate a point in a particular time series. | |
The formula to generate the time series is | |
p(t) = 100 + sum[sin(t * c_i)] for c_i in | |
c = [46, 64, 98, 99, 101, 104, 106, 107, 109, 110, 111, 111, 111, 115, 115] | |
Args: | |
t: Integer representing time | |
Returns: | |
Float | |
""" | |
c = [46, 64, 98, 99, 101, 104, 106, 107, 109, 110, 111, 111, 111, 115, 115] | |
result = 100 | |
for c_i in c: | |
result += math.sin(t * c_i) | |
return result | |
STOCK_TIME_SERIES = [generate_data_point(t) for t in range(260)] | |
def calculate_strategy_returns(stock_price_time_series): | |
""" Calculates returns of the following strategy applied to the input time series. | |
Hold the stock when it is within the open interval [98, 101] and | |
sell at the end of the time series if still holding. | |
Args: | |
stock_price_time_series: [List-of Float] representing stock price over time | |
Returns: | |
Float representing the amount gained by following the described strategy | |
""" | |
accumulated_returns = 0 | |
# how many points in the times series have we looked at | |
points_processed = 0 | |
# what was the price we last bought the stock out | |
last_bought_at = 0 | |
# are we currently holding the stock? | |
holding = False | |
for price in stock_price_time_series: | |
points_processed += 1 | |
if holding: | |
# we have the stock and it is the last point, then sell | |
if points_processed == len(stock_price_time_series): | |
accumulated_returns += price - last_bought_at | |
holding = False | |
log("S") | |
# continue holding stock | |
elif price >= 98 and price <= 101: | |
log("N") | |
# sell stock | |
else: | |
accumulated_returns += price - last_bought_at | |
holding = False | |
log("S") | |
else: | |
# buy stock | |
if price >= 98 and price <= 101: | |
log("B") | |
holding = True | |
last_bought_at = price | |
# else do nothing | |
else: | |
log("N") | |
return accumulated_returns | |
test("test strategy on series that breaks even", | |
calculate_strategy_returns([96, 97, 98, 102, 100, 100, 100, 96]) == 0) | |
# TODO: write more tests for calculate_strategy_returns | |
def strategy_to_percentage_return(stock_price_time_series): | |
""" Apply a strategy to stock price time series and calculate percentage returns at each step. | |
Args: | |
stock_price_time_series: [List-of Float] representing stock price over time | |
Returns: | |
[List-of Float] representing the percentage return at each point in time | |
""" | |
percentage_return_series = [] | |
# how many points in the times series have we looked at | |
points_processed = 0 | |
# what was the price we last bought the stock out | |
last_bought_at = 0 | |
# are we currently holding the stock? | |
holding = False | |
for price in stock_price_time_series: | |
points_processed += 1 | |
if holding: | |
# we have the stock and it is the last point, then sell | |
if points_processed == len(stock_price_time_series): | |
percentage_return_series.append((price - last_bought_at) / last_bought_at) | |
holding = False | |
log("S") | |
# continue holding stock | |
if price >= 98 and price <= 101: | |
percentage_return_series.append(0) | |
# sell stock | |
else: | |
percentage_return_series.append((price - last_bought_at) / last_bought_at) | |
holding = False | |
else: | |
# buy stock | |
if price >= 98 and price <= 101: | |
holding = True | |
last_bought_at = price | |
# XXX: Not sure if this is the correct percentage to append here | |
percentage_return_series.append(0) | |
# else do nothing | |
return percentage_return_series | |
# TODO: write tests for strategy_to_percentage_return | |
def total_cumulative_return(percentage_return_time_series): | |
""" Calculate the total cumulative return based on time series of individual return percentages. | |
Args: | |
percentage_return_time_series: [List-of Float] representing return percentage | |
Returns: | |
Float representing total return percentage | |
""" | |
# NOTE: Since I'm unfamiliar with cumulative percentage returns I'm | |
# following "Returns over multiple periods" formula from Wikipedia's "Rate | |
# of Return" page | |
cumulative_returns = 1 | |
for rate in percentage_return_time_series: | |
cumulative_returns *= (1 + rate) | |
return cumulative_returns - 1 | |
test("testing total return after two days of 10% gains", | |
total_cumulative_return([.1, .1]) >= .209 and | |
total_cumulative_return([.1, .1]) <= .211) | |
# What is the cumulative percentage return using this strategy: | |
# 1) simply on a percentage return basis | |
# e.g., day 1: 10%, day 2: 10%, total return would be 21% after two days. | |
print("Question 1: " + \ | |
"based on applying the strategy over the stock price time series the " + \ | |
"total cumulative return is", | |
total_cumulative_return(strategy_to_percentage_return(STOCK_TIME_SERIES))) | |
# 2) assuming $1000.00 of starting capital and only purchasing whole "shares" | |
# TODO | |
if __name__ == "__main__": | |
if INTERACTIVE_SHELL: | |
import code | |
code.interact(local=locals()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment