# -*- coding: utf-8 -*-
"""Session 1: Simple Moving Average Rule.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1KgtvSVkbG4_wAzOMOYAtogS18sDcGekG

# 1. Import Data

1.   Install the Alpha Vantage API
2.   [Claim your own API Key](https://www.alphavantage.co/support/#api-key)
3.   [Import data from Time Series Stock APIs by specifiying API key and Parameters](https://www.alphavantage.co/documentation/)

Install Alpha Vantage Package
"""



from alpha_vantage.timeseries import TimeSeries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

"""Program import data class

"""

class Data:
  def __init__(self,API_key, symbol):
    self.API_key = API_key
    self.symbol = symbol
  def import_data(self):
    ts = TimeSeries(key=self.API_key, output_format='pandas')
    data=ts.get_daily(self.symbol, outputsize = 'full')
    data[0].rename(columns={'1. open':'open', '2. high':'high', '3. low':'low', '4. close':'close', '5. volume':'volume'}, inplace = True)
    all_df = data[0]
    num = int(3/5 * all_df.shape[0])
    all_df.sort_index(ascending=True, inplace=True)
    df = all_df.iloc[num:].copy()
    return df

"""return data with specified API and parameters: 

we use Tesla (TSLA) and Apple (AAPL) with daily interval as case studies.  
"""


"""# 2. Generate buy and sell signals with Visualizations

Program the signal class

https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.rolling.html

```
# 此内容为代码格式
```

The Simple moving average with window $n$ at time $t$:

(1)     $$SMA_t^n=\frac{1}{n}\sum_{i=t-n+1}^{t}p_i$$
"""

class signal:
  def __init__(self, data, short_window, long_window):
    self.data = data
    self.short_window = short_window
    self.long_window = long_window
  def signals(self):
    signals = pd.DataFrame(index=self.data.index)
    signals = signals.sort_values(by='date')
    signals['signal'] = 0.0
    signals['short_ma'] = self.data['close'].rolling(window=self.short_window, min_periods=self.short_window, center=True, closed='right').mean()
    signals['long_ma'] = self.data['close'].rolling(window=self.long_window, min_periods=self.long_window, center=True, closed='right').mean()  
    signals['signal'][self.short_window:] = np.where(signals['short_ma'][self.short_window:]>signals['long_ma'][self.short_window:], 1.0, 0.0)     
    signals['positions'] = signals['signal'].diff()
    signals =signals.dropna()
    return signals

"""Return signals with input data and short and long windows. 

We use Tesla (TSLA) and Apple (AAPL) in a daily interval as case studies.

Short_window = 50

Long_window = 200
"""

"""define signal visualization class"""

class signal_figure:
  def __init__(self, prices, signals, topic):
    self.prices = prices
    self.signals = signals
    self.topic = topic
  def signal_figure(self):
    close = self.prices['close']
    close = close.to_frame()
    close = close.merge(self.signals,how='inner',left_index=True, right_index=True)
    close = close.sort_values(by='date')
    fig = plt.figure(figsize = (18,8))
    plt.plot(close.close, color='g', lw=1., label = 'Stock Price')
    plt.plot(close.short_ma, color='r', lw=1., label = 'Short Window Moving Average')
    plt.plot(close.long_ma, color='b', lw=1., label = 'Long Window Moving Average')
    plt.plot(close.loc[close.positions == 1.0].index, close.short_ma[close.positions == 1.0], '^', markersize=5, color='green',label = 'buying signal')
    plt.plot(close.loc[close.positions == -1.0].index, close.long_ma[close.positions == -1.0],'v', markersize=5, color='red',label = 'selling signal')
    plt.xlabel('Date')
    plt.ylabel('Dollars')
    plt.title(self.topic + ' Price')
    plt.legend()
    plt.show()
    return close

"""Return plots with input data."""


"""# 3. Generate Return of Investment and Portfolio Flows (cash, holding and total)

program the portfolio class
"""

class portfolio:
  def __init__(self,data,topic,initial_capital=10000,max_buy=10000000,max_sell=10000000):
    self.data = data
    self.topic = topic
    self.initial_capital = initial_capital
    self.max_buy = max_buy
    self.max_sell = max_sell
  def portfolios(self):
    management = self.data
    prices = self.data['close']
    states = self.data['positions']
    states_buy = []
    states_sell = []
    cashes = []
    stocks = []
    holdings = []
    cash = self.initial_capital
    stock = 0
    holding = 0
    state = 0
    def buy(i,cash,stock,price):
      shares = cash // price #shares to buy in integer
      if shares<1:
        print('order %d: total cash %f, not enough to buy 1 share at price %f' % (i, cash, price))
      else:
        if shares>self.max_buy:
            buy_units = self.max_buy
        else:
            buy_units = shares
        cost = buy_units*price
        cash -= cost
        stock += buy_units
        holding = stock*price
        print('index %d: buy %d units at price %f, current cash %f, current stock %f,current holding %f' % (i, buy_units, price, cash, stock, holding))
        return cash, stock, holding   
    def sell(i,cash, stock,price):
       if stock == 0:
         print('index %d: cannot sell anything, currentstock 0' % (i))
       else:
         if stock > self.max_sell:
            sell_units = self.max_sell
         else: 
            sell_units = stock
         stock -=sell_units
         revenue = sell_units*price
         cash += revenue
         holding = stock*price
         print('index %d: sell %d units at price %f, current cash %f, current stock %f,current holding %f' % (i, sell_units, price, cash, stock, holding))
         return cash, stock, holding
    for i in range(0,management.shape[0]):
      
      state = states[i]
      price = prices[i]
      if state == 1:
        cash, stock, holding = buy(i, cash, stock, price)
        states_buy.append(i)
      elif state == -1:
        cash, stock, holding = sell(i,cash, stock, price)
      states_sell.append(i)
      cashes.append(cash)
      stocks.append(stock)
      holdings.append(holding)
    
    management['cash']=cashes
    management['stock']=stocks
    management['holding']=holdings
    management['total']=management['cash']+management['holding']
  

    management['roi']=(management['total']-self.initial_capital)/self.initial_capital
    management["roi_buy&hold"]= (management["close"]-management["close"][0])/management["close"][0]

    management['sharpe'] = ""
    management["sharpe_buy&hold"] = ""
    
    for i in range(0, management.shape[0]):
      if management["roi"].iloc[0:i].std()==0:
        management["sharpe"][i]=0
      else:
        management["sharpe"][i]=np.mean(management["roi"].iloc[0:i])/management["roi"].iloc[0:i].std()

    for i in range(0, management.shape[0]):
      if management["roi_buy&hold"].iloc[0:i].std()==0:
        management["sharpe_buy&hold"][i]=0
      else:
        management["sharpe_buy&hold"][i]=np.mean(management["roi_buy&hold"].iloc[0:i])/management["roi_buy&hold"].iloc[0:i].std() 


    fig, (ax1, ax2, ax3) = plt.subplots(3,1, figsize = (15,20))
    ax1.plot(management['holding'], label='Holdings', color='r')
    ax1.plot(management['cash'], label="Cash", color='g')
    ax1.plot(management['total'], label="Total", color='b')
    ax1.set_title("Visualization of #"+ self.topic +" Portfolio Flows",fontsize=15)
    ax1.set_xlabel('Days',fontsize=10)
    ax1.set_ylabel('Total Holdings',fontsize=10)
    ax1.legend()
    
    ax2.plot(management["roi"],label="ROI_SMA_algorithm", color="b")
    ax2.plot(management["roi_buy&hold"],label="ROI_buy&hold", color="r")
    ax2.set_title("Comparison of #" + self.topic + " ROI on SMA and Simple Buy&Hold Strategy",fontsize=15)
    ax2.set_ylabel('ROI',fontsize=10)
    ax2.set_xlabel('Days',fontsize=10)
    ax2.legend()

    ax3.plot(management["sharpe"],label="sharpe_SMA_algorithm", color="b")
    ax3.plot(management["sharpe_buy&hold"],label="sharpe_buy&hold", color="r")
    ax3.set_title("Comparison of #" + self.topic +" Sharpe Ratio on SMA and Simple Buy&Hold Strategy",fontsize=15)
    ax3.set_ylabel('Sharpe Ratio',fontsize=10)
    ax3.set_xlabel('Days',fontsize=10)
    ax3.legend()

    return management

"""Return plots with input data."""



