
# -*- coding: utf-8 -*-
"""Simulation.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1tsqB4JK8Ev_DRlxyLnDoT__4zdqtPh8h
"""
import sys
sys.path.append(".")
# Commented out IPython magic to ensure Python compatibility.
from portfolio.data import Obtain_Data
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
# %matplotlib in line
import seaborn as sns
sns.set(style='darkgrid', context='talk', palette='Dark2')
my_year_month_fmt = mdates.DateFormatter('%m/%y')
from scipy.stats import norm

class Signal:
  def __init__(self,tweets_senti_price, days):
    self.tweets_senti_price = tweets_senti_price
    self.days = days

  def signals(self):
    signal= self.tweets_senti_price
    signal['ema_short'] = signal['Prices'].ewm(span=self.days, adjust=False).mean()
    signal['trading_positions_raw'] = signal['Prices'] - signal.ema_short
    mean_df =signal["P_Comp"].mean()
    std_p =signal["P_Comp"].std()
    std_ema=signal["trading_positions_raw"].std()
    left=mean_df-0.2*std_p
    right=mean_df+0.2*std_p
    signal['trading_positions'] = 0
    signal.loc[(signal['trading_positions_raw'] >0.5*std_ema) & (signal["P_Comp"] < left) , 'trading_positions'] = -1
    signal.loc[(signal['trading_positions_raw'] <-0.5*std_ema) & (signal["P_Comp"] > right), 'trading_positions'] = 1
    return signal


class Signal_Figure:
  def __init__(self, signal):
    self.signal = signal
   
  def signal_figure_raw_trading_positions(self):
    signal=self.signal
    buys = signal[signal['trading_positions'] == 1]
    sells = signal[signal['trading_positions'] == -1]
   
    fig, ax1 = plt.subplots(figsize=(25,10))
    ax1.plot(signal['Prices'], label='Adj Close', color='b')
    ax2 = ax1.twinx()
    ax2.plot(signal["trading_positions_raw"],label="raw trading positions",color="g")
    ax1.plot(signal.iloc[sells.index]['Prices'], 'v', markersize=15, color='b',label = 'selling signal')
    ax1.plot(signal.iloc[buys.index]['Prices'], '^', markersize=15, color='r',label = 'buying signal')
   
    ax2.axhline(0.5*signal["trading_positions_raw"].std(),0,150,linestyle = "--",label="upper limit")
    ax2.axhline(-0.5*signal["trading_positions_raw"].std(),0,150,linestyle = "--",label="lower limit")
    ax1.set_ylabel('Price',fontsize=20)
    ax1.set_xlabel('Days',fontsize=20)
    ax1.legend(loc=2)
    ax2.legend()
    ax1.set_title("Visualization of #"+"AAPL"+" Closed Price, Raw Trading Positions and Buy & Sell Signals",fontsize=20)
    plt.show()

  def signal_figure_sentiment_score(self):
    signal=self.signal
    buys = signal[signal['trading_positions'] == 1]
    sells = signal[signal['trading_positions'] == -1]
    fig, ax1 = plt.subplots(figsize=(25,10))
    ax1.plot(signal['Prices'], label='Adj Close', color='b')
    ax2 = ax1.twinx()
    ax2.plot(signal["P_Comp"],label="Sentiment score",color="g")
    ax1.plot(signal.iloc[sells.index]['Prices'], 'v', markersize=15, color='b',label = 'selling signal')
    ax1.plot(signal.iloc[buys.index]['Prices'], '^', markersize=15, color='r',label = 'buying signal')
    ax2.axhline(signal["P_Comp"].mean()-0.2*signal["P_Comp"].std(),0,150,linestyle = "--",label="mean-0.2STD")
    ax2.axhline(signal["P_Comp"].mean()+0.2*signal["P_Comp"].std(),0,150,linestyle = "--",label="mean+0.2STD")
    ax1.set_ylabel('Price',fontsize=20)
    ax1.set_xlabel('Days',fontsize=20)
    ax1.legend(loc=4)
    ax1.set_title("Visualization of #"+"AAPL"+" Closed Price, Sentiment and Buy & Sell Signals",fontsize=20)
    ax2.legend()
    plt.show()

class Portfolio:
  def __init__(self,data,initial_capital=100000,max_buy=10000000,max_sell=100000000):
    self.data = data
    self.initial_capital = initial_capital
    self.max_buy = max_buy
    self.max_sell = max_sell
    self.management=[]
  def portfolios(self):
    management = self.data
    prices = self.data['Prices']
    states = self.data['trading_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:
        cash=cash
        stock=stock
        price=price
        holding=stock*price
        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 -= buy_units*price
        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))
         cash=cash
         stock=stock
         price=price
         holding=stock*price
      else:
        if stock > self.max_sell:
            sell_units = self.max_sell
        else: 
            sell_units = stock
        stock -=sell_units
        revenue = sell_units*price
        cash += revenue
        price=price
        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)
        print(states_buy)
      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["Prices"]-management["Prices"][0])/management["Prices"][0]

    management["sharpe"]= ""
    management["sharpe_buy&hold"]= ""


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

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

    management.to_csv("management.csv")


    fig, (ax1,ax2,ax3,ax4) = plt.subplots(4,1,figsize=(25,60))
    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 #"+ "AAPL" +" Portfolio Flows",fontsize=20)
    ax1.set_xlabel('Days',fontsize=20)
    ax1.set_ylabel('Total Holdings',fontsize=20)
    ax1.legend()
    print()
    print("During the time of evaluation, the algorithm generates "+ str(len(management[management["trading_positions"]==1])) +" buying signals and "+str(len(management[management["trading_positions"]==-1])) +" selling signals.")

    ax2.plot(management["roi"],label="Return on Investment", color="b")
    ax2.set_title("Visualization of #"+ "AAPL" +" Return on Investment",fontsize=20)
    ax2.set_ylabel('ROI',fontsize=20)
    ax2.set_xlabel('Days',fontsize=20)
    ax2.legend()

    ax3.plot(management["roi"],label="ROI_algorithm", color="b")
    ax3.plot(management["roi_buy&hold"],label="ROI_buy&hold", color="r")
    ax3.set_title("Comparison of ROI on Newsreader Algorithm and Simple Buy&Hold Strategy",fontsize=20)
    ax3.set_ylabel('ROI',fontsize=20)
    ax3.set_xlabel('Days',fontsize=20)
    ax3.legend()

    ax4.plot(management["sharpe"],label="sharpe_algorithm", color="b")
    ax4.plot(management["sharpe_buy&hold"],label="sharpe_buy&hold", color="r")
    ax4.set_title("Comparison of Sharpe Ratio on Newsreader Algorithm and Simple Buy&Hold Strategy",fontsize=20)
    ax4.set_ylabel('Sharpe Ratio',fontsize=20)
    ax4.set_xlabel('Days',fontsize=20)
    ax4.legend()

    return management

    
class Simulation:
  def __init__(self, stock_id, start, end):
    self.dataset= Obtain_Data(stock_id=stock_id, start=start, end=end)
    self.final_dataset=self.dataset.getdata()
    self.signals= Signal(self.final_dataset,10)
    self.signal= self.signals.signals()
    self.signal_figure = Signal_Figure(self.signal)
    self.portfolio = Portfolio(self.signal,initial_capital=100000,max_buy=10000000,max_sell=100000000)

  def getsignal(self):
    return self.signal
  def signal_raw_position_graph(self):
    return self.signal_figure.signal_figure_raw_trading_positions()
  def signal_senti_graph(self):
    return self.signal_figure.signal_figure_sentiment_score()
  def get_portfolio(self):
    return self.portfolio.portfolios()
