import pandas as pd
import pandas.io.data as web

import numpy as np
import datetime

msft = pd.read_csv("msft.csv", index_col=0, parse_dates=True)
aapl = pd.read_csv("aapl.csv", index_col=0, parse_dates=True)

msft['2012-01']

"""
Explanation: Task
In this assignment, you will implement simple algorithmic trading policies and modify a very simple backtester.
In the following, you will find a Backtester1 function that gets as an input the historical price series of a single stock.
At each time interval, the backtester calls for a new order (by calling the placeOrder function), along with the current opening price. Depending upon the current position of the customer (number of owned stocks and current cash), the customer decides upon a new investment. This is currently a random decision, merely deciding the percentage of capital to leave on a stocks. Consequently, the PlaceOrder function will return one of the following orders, to realize the decided position:

Buy <number of stocks>
Sell <number of stocks>

PlaceOrder assumes that stocks can be traded only as integer multiples.
Task 1
Modify the program to create plots of the total wealth over time, along with the value of the stocks and cash at each time point. 
Task 2
Add the following type of orders that a customer can issue
* AddCapital <amount>
* WithdrawCapital <amount>
The backtester should always keep track of the position of the trader and make appropriate checks, such as only allowing buying stocks allowed by the current capital.
Task 3
Add an interest_rate such that at the beginning of each trading day, the cash earns a fixed interest. Also, include transaction costs (a fixed percentage of the trade) to be deduced from each transaction.
Task 4
Modify the system such that it allows for open selling, that is selling without actually owning any stock. At the end of the trading day, any open positions should be cleared by the closing price.
Task 5
Think and implement a trading policy of your imagination, such as estimating the trend in the last few days, and coming up with a smarter decision than random. Compare your policy with the random policy in terms of earnings or losses.
Task 6
Modify the program such that you allow for pairs trading. Modify the backtester such that you input a pair of stocks. Now the generated investment decisions must be portfolio. Repeat task 5 for the pairs case.
Read some example Data
End of explanation
"""



InitialCash = 1000
Position = {'Cash': InitialCash, 'Stocks': 0.0} 

def DecideTargetPosition():
    ## Randomly decide a portfolio output percentage of capital to put into stocks
    return np.random.choice([0.0, 0.5, 1.0])        
        
def Capital(price):
    return Position['Cash'] + Position['Stocks']*price
        
def PlaceOrder(price):
    p = DecideTargetPosition()
    capital = Capital(price)
        
    numLots = np.floor(capital*p/price)
        
    TargetPosition = {'Cash': capital-numLots*price, 'Stocks': numLots}
        
    if TargetPosition['Stocks'] > Position['Stocks']:
        # Buy 
        order = ('Buy', TargetPosition['Stocks']-Position['Stocks'])
        return order
    elif TargetPosition['Stocks'] < Position['Stocks']:
        # Sell
        order = ('Sell', -TargetPosition['Stocks']+Position['Stocks'])
        return order
    else:
        # Do nothing
        None
            
def UpdatePosition(deltaCash, deltaStock):
    Position['Cash'] += deltaCash
    Position['Stocks'] += deltaStock
    return


def BackTester1(series, interest_rate):
    
    openPrice = series['Open']
    closePrice = series['Close']
        
    for k in openPrice.keys():
        price = openPrice[k]
        order = PlaceOrder(price) 
        
        if order is None:
            continue
            
        print order
        
        if order[0]=='Buy':
            deltaCash = -price*order[1]
            deltaStock = order[1]
            UpdatePosition(deltaCash, deltaStock)
        elif order[0]=='Sell':
            deltaCash = price*order[1]
            deltaStock = -order[1]            
            UpdatePosition(deltaCash, deltaStock)
        else:
            None
            
        price = closePrice[k]
        print k, Capital(price)
    
InitialCash = 1000
Position = {'Cash': InitialCash, 'Stocks': 0.0} 

BackTester1(msft['2012-01'], 0.05)

"""
Explanation: A reference implementation
End of explanation
"""



class Customer:
    def __init__(self, cash=10000):
        self.Position = {'Cash': cash, 'Stocks': 0.0} 

    def DecideTargetPosition(self):
        ## Randomly decide a portfolio output percentage of capital to put into stocks
        return np.random.choice([0.0, 0.5, 1.0])        
        
    def Capital(self, price):
        return self.Position['Cash'] + self.Position['Stocks']*price
        
    def PlaceOrder(self, price):
        p = self.DecideTargetPosition()
        capital = self.Capital(price)
        
        numLots = np.floor(capital*p/price)
        
        TargetPosition = {'Cash': capital-numLots*price, 'Stocks': numLots}
        
        if TargetPosition['Stocks']>self.Position['Stocks']:
            # Buy 
            return ('Buy', TargetPosition['Stocks']-self.Position['Stocks'])
        elif TargetPosition['Stocks']<self.Position['Stocks']:
            # Sell
            return ('Sell', -TargetPosition['Stocks']+self.Position['Stocks'])
        else:
            # Do nothing
            None
            
    def GetPosition(self):
        return self.Position
    def UpdatePosition(self, deltaCash, deltaStock):
        self.Position['Cash'] += deltaCash
        self.Position['Stocks'] += deltaStock
        return

def BackTester(series, customer, interest_rate):
    
    openPrice = series['Open']
    closePrice = series['Close']
        
    for k in openPrice.keys():
        price = openPrice[k]
        order = customer.PlaceOrder(price) 
        
        if order is None:
            continue
            
        print order
        
        if order[0]=='Buy':
            deltaCash = -price*order[1]
            deltaStock = order[1]
            customer.UpdatePosition(deltaCash, deltaStock)
        elif order[0]=='Sell':
            deltaCash = price*order[1]
            deltaStock = -order[1]            
            customer.UpdatePosition(deltaCash, deltaStock)
        else:
            None
            
        price = closePrice[k]
        print k, customer.Capital(price)
    
Cash = 1000
cust = Customer(cash=Cash)

BackTester(msft['2012-01'], cust, 0.05)

"""
Explanation: A cleaner implementation with the use of class constructs
End of explanation
"""


