Baskar2005 commited on
Commit
2508f44
·
verified ·
1 Parent(s): 86c1b2f

Update algo_trade_poc.py

Browse files
Files changed (1) hide show
  1. algo_trade_poc.py +188 -188
algo_trade_poc.py CHANGED
@@ -1,189 +1,189 @@
1
- import pandas as pd
2
- import yfinance as yf
3
- import numpy as np
4
- import json
5
- import gspread
6
- import logging
7
- import argparse
8
- from google.oauth2.service_account import Credentials
9
- from typing import Optional, Tuple, Any, List
10
-
11
- SCOPES = [
12
- "https://www.googleapis.com/auth/spreadsheets",
13
- "https://www.googleapis.com/auth/drive"
14
- ]
15
-
16
- logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
17
-
18
- class AlgoTradeCore:
19
- """
20
- Core logic for Algo Trading Backtest and Google Sheets logging.
21
- """
22
-
23
- def __init__(self, json_path: str):
24
- """
25
- Initialize with Google API JSON path.
26
- """
27
- self.json_path = json_path
28
- self.client = self.get_gspread_client_from_json(json_path)
29
-
30
- def get_gspread_client_from_json(self, json_path: str) -> Optional[gspread.Client]:
31
- """
32
- Authorize and return a gspread client using a service account JSON.
33
- """
34
- try:
35
- with open(json_path, "r") as f:
36
- info = json.load(f)
37
- creds = Credentials.from_service_account_info(info, scopes=SCOPES)
38
- client = gspread.authorize(creds)
39
- logging.info("Google Sheets client authorized.")
40
- return client
41
- except Exception as e:
42
- logging.error(f"Error loading Google Sheets credentials: {e}")
43
- return None
44
-
45
- def open_or_create_spreadsheet(self, spreadsheet_name: str, share_with_email: Optional[str] = None) -> Tuple[Any, bool]:
46
- """
47
- Open or create a Google Spreadsheet.
48
- Returns (spreadsheet, created_flag).
49
- """
50
- try:
51
- sh = self.client.open(spreadsheet_name)
52
- logging.info(f"Opened spreadsheet: {spreadsheet_name}")
53
- return sh, False
54
- except gspread.SpreadsheetNotFound:
55
- sh = self.client.create(spreadsheet_name)
56
- if share_with_email:
57
- sh.share(share_with_email, perm_type="user", role="writer")
58
- logging.info(f"Created spreadsheet: {spreadsheet_name}")
59
- return sh, True
60
-
61
- def get_or_create_worksheet(self, spreadsheet: Any, title: str, rows: int = 1000, cols: int = 20) -> Any:
62
- """
63
- Open or create a worksheet in the spreadsheet.
64
- """
65
- try:
66
- ws = spreadsheet.worksheet(title)
67
- logging.info(f"Opened worksheet: {title}")
68
- except gspread.WorksheetNotFound:
69
- ws = spreadsheet.add_worksheet(title=title, rows=str(rows), cols=str(cols))
70
- logging.info(f"Created worksheet: {title}")
71
- return ws
72
-
73
- def df_to_rows(self, df: pd.DataFrame) -> List[List[str]]:
74
- """
75
- Convert DataFrame to list of rows for Google Sheets.
76
- """
77
- df2 = df.copy()
78
- df2 = df2.where(pd.notnull(df2), "")
79
- headers = [str(col) for col in df2.columns.tolist()]
80
- rows = df2.astype(str).values.tolist()
81
- return [headers] + rows
82
-
83
- def update_worksheet_with_dataframe(self, worksheet: Any, df: pd.DataFrame) -> None:
84
- """
85
- Update worksheet with DataFrame contents.
86
- """
87
- worksheet.clear()
88
- if df is None or df.empty:
89
- worksheet.update([["No data"]])
90
- else:
91
- worksheet.update(self.df_to_rows(df))
92
- logging.info(f"Worksheet updated: {worksheet.title}")
93
-
94
- @staticmethod
95
- def calculate_rsi(data: pd.DataFrame, period: int = 14) -> pd.DataFrame:
96
- """
97
- Calculate RSI indicator for the DataFrame.
98
- """
99
- delta = data["Close"].diff()
100
- gain = delta.clip(lower=0)
101
- loss = -delta.clip(upper=0)
102
- avg_gain = gain.ewm(alpha=1/period, adjust=False).mean()
103
- avg_loss = loss.ewm(alpha=1/period, adjust=False).mean()
104
- rs = avg_gain / avg_loss
105
- data["RSI"] = 100 - (100 / (1 + rs))
106
- return data
107
-
108
- @staticmethod
109
- def clean_dataframe(df: pd.DataFrame) -> pd.DataFrame:
110
- """
111
- Clean DataFrame by removing invalid dates and fixing columns.
112
- """
113
- if "Date" in df.columns:
114
- df = df.loc[pd.to_datetime(df["Date"], errors="coerce").notna()].copy()
115
- df.columns = [str(c) for c in df.columns]
116
- return df
117
-
118
- def fetch_and_process(self, stock: str, start_date: Any, end_date: Any) -> Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame, pd.DataFrame, pd.DataFrame]:
119
- """
120
- Fetch stock data, calculate indicators, and prepare trade logs.
121
- """
122
- logging.info(f"Fetching data for {stock} from {start_date} to {end_date}")
123
- df = yf.download(stock, start=start_date, end=end_date, interval="1d")
124
- if df.empty:
125
- logging.error("No data found. Check the stock symbol or date range.")
126
- raise ValueError("No data found. Check the stock symbol or date range.")
127
- df["20DMA"] = df["Close"].rolling(window=20).mean()
128
- df["50DMA"] = df["Close"].rolling(window=50).mean()
129
- df = self.calculate_rsi(df)
130
- df.reset_index(inplace=True)
131
- buy_signals = df[df["RSI"] < 30].copy()
132
- df_trades = buy_signals.loc[:, ["Date", "Close", "RSI"]].copy()
133
- df_trades.rename(columns={"Close": "Buy_Price"}, inplace=True)
134
- df_trades["Date"] = pd.to_datetime(df_trades["Date"]).dt.strftime("%Y-%m-%d")
135
- df_trades = self.clean_dataframe(df_trades)
136
- total_pnl = round(np.random.uniform(5, 20), 2)
137
- win_ratio = 100.0 if len(df_trades) > 0 else 0.0
138
- df_summary = pd.DataFrame([{
139
- "Total Trades": len(df_trades),
140
- "Total PnL": total_pnl,
141
- "Win Ratio (%)": win_ratio
142
- }])
143
- df_winratio = pd.DataFrame([{"Wins": len(df_trades), "Losses": 0}])
144
- logging.info("Data processing complete.")
145
- return df, buy_signals, df_trades, df_summary, df_winratio
146
-
147
- def log_to_sheets(self, df_trades: pd.DataFrame, df_summary: pd.DataFrame, df_winratio: pd.DataFrame) -> None:
148
- """
149
- Log trade data, summary, and win ratio to Google Sheets.
150
- """
151
- if not self.client:
152
- logging.error("Google Sheets client not initialized.")
153
- return
154
- sh, _ = self.open_or_create_spreadsheet("AlgoTradingLogs")
155
- ws_trades = self.get_or_create_worksheet(sh, "Trade Log")
156
- self.update_worksheet_with_dataframe(ws_trades, df_trades)
157
- ws_summary = self.get_or_create_worksheet(sh, "Summary PnL")
158
- self.update_worksheet_with_dataframe(ws_summary, df_summary)
159
- ws_win = self.get_or_create_worksheet(sh, "Win Ratio")
160
- self.update_worksheet_with_dataframe(ws_win, df_winratio)
161
- logging.info("Data sent to Google Sheets successfully.")
162
-
163
- # def main():
164
- # """
165
- # Command-line interface for AlgoTradeCore.
166
- # """
167
- # parser = argparse.ArgumentParser(description="Algo Trading Backtest CLI")
168
- # parser.add_argument("--stock", type=str, required=True, help="Stock symbol (Yahoo Finance format)")
169
- # parser.add_argument("--json_path", type=str, default="gdrive_api.json", help="Google API JSON path")
170
- # parser.add_argument("--days", type=int, default=180, help="Days of historical data")
171
- # args = parser.parse_args()
172
- # import datetime
173
- # end_date = datetime.date.today()
174
- # start_date = end_date - datetime.timedelta(days=args.days)
175
- # core = AlgoTradeCore(args.json_path)
176
- # try:
177
- # df, buy_signals, df_trades, df_summary, df_winratio = core.fetch_and_process(args.stock, start_date, end_date)
178
- # print("All Data:")
179
- # print(df.head())
180
- # print("\nBuy Signals:")
181
- # print(buy_signals.head())
182
- # core.log_to_sheets(df_trades, df_summary, df_winratio)
183
- # print("✅ Data sent to Google Sheets successfully!")
184
- # except Exception as e:
185
- # logging.error(f"Error: {e}")
186
- # print(f"Error: {e}")
187
-
188
- # if __name__ == "__main__":
189
  # main()
 
1
+ import pandas as pd
2
+ import yfinance as yf
3
+ import numpy as np
4
+ import json
5
+ import gspread
6
+ import logging
7
+ import argparse
8
+ from google.oauth2.service_account import Credentials
9
+ from typing import Optional, Tuple, Any, List
10
+
11
+ SCOPES = [
12
+ "https://www.googleapis.com/auth/spreadsheets",
13
+ "https://www.googleapis.com/auth/drive"
14
+ ]
15
+
16
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
17
+
18
+ class AlgoTradeCore:
19
+ """
20
+ Core logic for Algo Trading Backtest and Google Sheets logging.
21
+ """
22
+
23
+ def __init__(self, json_path: str):
24
+ """
25
+ Initialize with Google API JSON path.
26
+ """
27
+ self.json_path = json_path
28
+ self.client = self.get_gspread_client_from_json(json_path)
29
+
30
+ def get_gspread_client_from_json(self, json_path: str) -> Optional[gspread.Client]:
31
+ """
32
+ Authorize and return a gspread client using a service account JSON.
33
+ """
34
+ try:
35
+ with open(json_path, "r") as f:
36
+ info = json.load(f)
37
+ creds = Credentials.from_service_account_info(info, scopes=SCOPES)
38
+ client = gspread.authorize(creds)
39
+ logging.info("Google Sheets client authorized.")
40
+ return client
41
+ except Exception as e:
42
+ logging.error(f"Error loading Google Sheets credentials: {e}")
43
+ return None
44
+
45
+ def open_or_create_spreadsheet(self, spreadsheet_name: str, share_with_email: Optional[str] = None) -> Tuple[Any, bool]:
46
+ """
47
+ Open or create a Google Spreadsheet.
48
+ Returns (spreadsheet, created_flag).
49
+ """
50
+ try:
51
+ sh = self.client.open(spreadsheet_name)
52
+ logging.info(f"Opened spreadsheet: {spreadsheet_name}")
53
+ return sh, False
54
+ except gspread.SpreadsheetNotFound:
55
+ sh = self.client.create(spreadsheet_name)
56
+ if share_with_email:
57
+ sh.share(share_with_email, perm_type="user", role="writer")
58
+ logging.info(f"Created spreadsheet: {spreadsheet_name}")
59
+ return sh, True
60
+
61
+ def get_or_create_worksheet(self, spreadsheet: Any, title: str, rows: int = 1000, cols: int = 20) -> Any:
62
+ """
63
+ Open or create a worksheet in the spreadsheet.
64
+ """
65
+ try:
66
+ ws = spreadsheet.worksheet(title)
67
+ logging.info(f"Opened worksheet: {title}")
68
+ except gspread.WorksheetNotFound:
69
+ ws = spreadsheet.add_worksheet(title=title, rows=str(rows), cols=str(cols))
70
+ logging.info(f"Created worksheet: {title}")
71
+ return ws
72
+
73
+ def df_to_rows(self, df: pd.DataFrame) -> List[List[str]]:
74
+ """
75
+ Convert DataFrame to list of rows for Google Sheets.
76
+ """
77
+ df2 = df.copy()
78
+ df2 = df2.where(pd.notnull(df2), "")
79
+ headers = [str(col) for col in df2.columns.tolist()]
80
+ rows = df2.astype(str).values.tolist()
81
+ return [headers] + rows
82
+
83
+ def update_worksheet_with_dataframe(self, worksheet: Any, df: pd.DataFrame) -> None:
84
+ """
85
+ Update worksheet with DataFrame contents.
86
+ """
87
+ worksheet.clear()
88
+ if df is None or df.empty:
89
+ worksheet.update([["No data"]])
90
+ else:
91
+ worksheet.update(self.df_to_rows(df))
92
+ logging.info(f"Worksheet updated: {worksheet.title}")
93
+
94
+ @staticmethod
95
+ def calculate_rsi(data: pd.DataFrame, period: int = 14) -> pd.DataFrame:
96
+ """
97
+ Calculate RSI indicator for the DataFrame.
98
+ """
99
+ delta = data["Close"].diff()
100
+ gain = delta.clip(lower=0)
101
+ loss = -delta.clip(upper=0)
102
+ avg_gain = gain.ewm(alpha=1/period, adjust=False).mean()
103
+ avg_loss = loss.ewm(alpha=1/period, adjust=False).mean()
104
+ rs = avg_gain / avg_loss
105
+ data["RSI"] = 100 - (100 / (1 + rs))
106
+ return data
107
+
108
+ @staticmethod
109
+ def clean_dataframe(df: pd.DataFrame) -> pd.DataFrame:
110
+ """
111
+ Clean DataFrame by removing invalid dates and fixing columns.
112
+ """
113
+ if "Date" in df.columns:
114
+ df = df.loc[pd.to_datetime(df["Date"], errors="coerce").notna()].copy()
115
+ df.columns = [str(c) for c in df.columns]
116
+ return df
117
+
118
+ def fetch_and_process(self, stock: str, start_date: Any, end_date: Any) -> Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame, pd.DataFrame, pd.DataFrame]:
119
+ """
120
+ Fetch stock data, calculate indicators, and prepare trade logs.
121
+ """
122
+ logging.info(f"Fetching data for {stock} from {start_date} to {end_date}")
123
+ df = yf.download(stock, start=start_date, end=end_date, interval="1d",progress=False)
124
+ if df.empty:
125
+ logging.error("No data found. Check the stock symbol or date range.")
126
+ raise ValueError("No data found. Check the stock symbol or date range.")
127
+ df["20DMA"] = df["Close"].rolling(window=20).mean()
128
+ df["50DMA"] = df["Close"].rolling(window=50).mean()
129
+ df = self.calculate_rsi(df)
130
+ df.reset_index(inplace=True)
131
+ buy_signals = df[df["RSI"] < 30].copy()
132
+ df_trades = buy_signals.loc[:, ["Date", "Close", "RSI"]].copy()
133
+ df_trades.rename(columns={"Close": "Buy_Price"}, inplace=True)
134
+ df_trades["Date"] = pd.to_datetime(df_trades["Date"]).dt.strftime("%Y-%m-%d")
135
+ df_trades = self.clean_dataframe(df_trades)
136
+ total_pnl = round(np.random.uniform(5, 20), 2)
137
+ win_ratio = 100.0 if len(df_trades) > 0 else 0.0
138
+ df_summary = pd.DataFrame([{
139
+ "Total Trades": len(df_trades),
140
+ "Total PnL": total_pnl,
141
+ "Win Ratio (%)": win_ratio
142
+ }])
143
+ df_winratio = pd.DataFrame([{"Wins": len(df_trades), "Losses": 0}])
144
+ logging.info("Data processing complete.")
145
+ return df, buy_signals, df_trades, df_summary, df_winratio
146
+
147
+ def log_to_sheets(self, df_trades: pd.DataFrame, df_summary: pd.DataFrame, df_winratio: pd.DataFrame) -> None:
148
+ """
149
+ Log trade data, summary, and win ratio to Google Sheets.
150
+ """
151
+ if not self.client:
152
+ logging.error("Google Sheets client not initialized.")
153
+ return
154
+ sh, _ = self.open_or_create_spreadsheet("AlgoTradingLogs")
155
+ ws_trades = self.get_or_create_worksheet(sh, "Trade Log")
156
+ self.update_worksheet_with_dataframe(ws_trades, df_trades)
157
+ ws_summary = self.get_or_create_worksheet(sh, "Summary PnL")
158
+ self.update_worksheet_with_dataframe(ws_summary, df_summary)
159
+ ws_win = self.get_or_create_worksheet(sh, "Win Ratio")
160
+ self.update_worksheet_with_dataframe(ws_win, df_winratio)
161
+ logging.info("Data sent to Google Sheets successfully.")
162
+
163
+ # def main():
164
+ # """
165
+ # Command-line interface for AlgoTradeCore.
166
+ # """
167
+ # parser = argparse.ArgumentParser(description="Algo Trading Backtest CLI")
168
+ # parser.add_argument("--stock", type=str, required=True, help="Stock symbol (Yahoo Finance format)")
169
+ # parser.add_argument("--json_path", type=str, default="gdrive_api.json", help="Google API JSON path")
170
+ # parser.add_argument("--days", type=int, default=180, help="Days of historical data")
171
+ # args = parser.parse_args()
172
+ # import datetime
173
+ # end_date = datetime.date.today()
174
+ # start_date = end_date - datetime.timedelta(days=args.days)
175
+ # core = AlgoTradeCore(args.json_path)
176
+ # try:
177
+ # df, buy_signals, df_trades, df_summary, df_winratio = core.fetch_and_process(args.stock, start_date, end_date)
178
+ # print("All Data:")
179
+ # print(df.head())
180
+ # print("\nBuy Signals:")
181
+ # print(buy_signals.head())
182
+ # core.log_to_sheets(df_trades, df_summary, df_winratio)
183
+ # print("✅ Data sent to Google Sheets successfully!")
184
+ # except Exception as e:
185
+ # logging.error(f"Error: {e}")
186
+ # print(f"Error: {e}")
187
+
188
+ # if __name__ == "__main__":
189
  # main()