Spaces:
Sleeping
Sleeping
gjin10969
commited on
Commit
·
e97cf97
1
Parent(s):
2b1b0fd
initialize
Browse files- ADA.png +0 -0
- ADA_USDT.png +0 -0
- ATOM_USDT.png +0 -0
- XRP_USDT.png +0 -0
- YOLO_WITH_ZSCORE/data.py +61 -0
- __pycache__/plotly.cpython-312.pyc +0 -0
- ada_usdt_1h.png +0 -0
- ada_usdt_4h.png +0 -0
- alarm.py +226 -0
- app.py +0 -5
- atom_usdt_1h.png +0 -0
- atom_usdt_4h.png +0 -0
- image_coordinate.py +54 -0
- main_with_plot copy.py +205 -0
- main_with_plot.py +193 -0
- main_with_plot_image_send.py +196 -0
- signals.json +134 -0
- xrp_usdt_1h.png +0 -0
- xrp_usdt_4h.png +0 -0
- yolo11n.pt +3 -0
- zscore_backtest.py +213 -0
ADA.png
ADDED
![]() |
ADA_USDT.png
ADDED
![]() |
ATOM_USDT.png
ADDED
![]() |
XRP_USDT.png
ADDED
![]() |
YOLO_WITH_ZSCORE/data.py
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import os
|
3 |
+
|
4 |
+
# Load YOLO detection data (from the given file)
|
5 |
+
yolo_file_path = '/media/gjin/New Volume/BACKTEST_DATA/black_edition_rolling_window_20_candlestick_5/json_data_folder/LINK_USDT_2024-12-02/LINK_USDT_17-27-55.json'
|
6 |
+
|
7 |
+
with open(yolo_file_path, 'r') as f:
|
8 |
+
yolo_data = json.load(f)
|
9 |
+
|
10 |
+
# Load Zscore signal data (from the given file)
|
11 |
+
zscore_file_path = '/home/gjin/Documents/zscore/signalsLINK.json'
|
12 |
+
|
13 |
+
with open(zscore_file_path, 'r') as f:
|
14 |
+
zscore_data = json.load(f)
|
15 |
+
|
16 |
+
# Define a function to update the YOLO trend based on zscore detection
|
17 |
+
def update_trend_with_zscore(yolo_data, zscore_data):
|
18 |
+
for yolo_entry in yolo_data:
|
19 |
+
symbol = yolo_entry['symbol']
|
20 |
+
date_and_time = yolo_entry['date_and_time']
|
21 |
+
|
22 |
+
# Normalize the symbol from zscore data (remove slash to match YOLO format)
|
23 |
+
normalized_symbol = symbol.replace('/', '') # Example: "ADA/USDT" becomes "ADAUSDT"
|
24 |
+
|
25 |
+
# Match the YOLO entry with the zscore entry by symbol and timestamp
|
26 |
+
zscore_entry = next((item for item in zscore_data if item['symbol'].replace('/', '') == normalized_symbol and item['date_and_time'] == date_and_time), None)
|
27 |
+
|
28 |
+
if zscore_entry:
|
29 |
+
# If zscore detection is True and trend is "no trend", keep it as "no trend"
|
30 |
+
if zscore_entry['detection'] == 'True':
|
31 |
+
# Do not modify the trend if already set
|
32 |
+
if yolo_entry['trend'] == "no trend":
|
33 |
+
# Only set zscore detection flag if trend is "no trend"
|
34 |
+
yolo_entry['zscore_detection'] = True
|
35 |
+
else:
|
36 |
+
# Keep existing trend, just add zscore detection flag
|
37 |
+
if 'zscore_detection' not in yolo_entry:
|
38 |
+
yolo_entry['zscore_detection'] = True
|
39 |
+
else:
|
40 |
+
# If zscore detection is False, set the trend to "no trend based on zscore detection"
|
41 |
+
yolo_entry['trend'] = "no trend based on zscore detection"
|
42 |
+
if 'zscore_detection' in yolo_entry:
|
43 |
+
del yolo_entry['zscore_detection']
|
44 |
+
|
45 |
+
else:
|
46 |
+
print(f"No zscore data found for {symbol} at {date_and_time}")
|
47 |
+
|
48 |
+
# Apply the function to update the YOLO data
|
49 |
+
update_trend_with_zscore(yolo_data, zscore_data)
|
50 |
+
|
51 |
+
# Define the output file path where the updated YOLO data will be saved
|
52 |
+
output_file_path = '/home/gjin/Documents/zscore/YOLO_WITH_ZSCORE/LINK_USDT_19-09-41_updated.json'
|
53 |
+
|
54 |
+
# Ensure the directory exists
|
55 |
+
os.makedirs(os.path.dirname(output_file_path), exist_ok=True)
|
56 |
+
|
57 |
+
# Save the updated YOLO data to the output file
|
58 |
+
with open(output_file_path, 'w') as f:
|
59 |
+
json.dump(yolo_data, f, indent=4)
|
60 |
+
|
61 |
+
print(f"Updated YOLO data has been saved to {output_file_path}")
|
__pycache__/plotly.cpython-312.pyc
ADDED
Binary file (7.64 kB). View file
|
|
ada_usdt_1h.png
ADDED
![]() |
ada_usdt_4h.png
ADDED
![]() |
alarm.py
ADDED
@@ -0,0 +1,226 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import os
|
3 |
+
# import pyttsx3
|
4 |
+
import telepot # Import the Telepot library
|
5 |
+
from datetime import datetime, timedelta, timezone
|
6 |
+
from apscheduler.schedulers.blocking import BlockingScheduler
|
7 |
+
from apscheduler.triggers.cron import CronTrigger
|
8 |
+
import time # Import the time module for sleep functionality
|
9 |
+
|
10 |
+
# Path to the signals JSON file
|
11 |
+
json_file_path = "/home/gjin/Documents/zscore/signals.json"
|
12 |
+
|
13 |
+
# Telegram bot credentials
|
14 |
+
BOT_TOKEN = '6787349532:AAGSwuiEJeykI2rQgsoB8C_iXZYKYuJyoOM' # Replace with your bot token
|
15 |
+
CHAT_ID = '-4284060853' # Replace with your chat ID
|
16 |
+
|
17 |
+
# Initialize the Telegram bot
|
18 |
+
bot = telepot.Bot(BOT_TOKEN)
|
19 |
+
|
20 |
+
# Initialize the pyttsx3 engine
|
21 |
+
# engine = pyttsx3.init()
|
22 |
+
|
23 |
+
# # Set a more natural speaking rate (around 150-160 words per minute)
|
24 |
+
# engine.setProperty('rate', 155) # Adjust this as needed
|
25 |
+
# engine.setProperty('volume', 1.0) # Max volume (range: 0.0 to 1.0)
|
26 |
+
|
27 |
+
# Maintain a set of already processed alarms
|
28 |
+
triggered_alarms = set()
|
29 |
+
|
30 |
+
# Function to play alarm sound
|
31 |
+
def play_alarm_sound():
|
32 |
+
try:
|
33 |
+
os.system("echo -e '\a'") # Produces a beep sound on Linux/Unix. For Windows, use `winsound.Beep()`.
|
34 |
+
except Exception as e:
|
35 |
+
print(f"Error playing sound: {e}")
|
36 |
+
|
37 |
+
# Function to speak the output (symbol, signal, zscore)
|
38 |
+
# def speak_zscore_signal(symbol, signal, zscore, timeframe, realtime_ph_time):
|
39 |
+
# message = f"The signal for {symbol} is {signal} with a zscore of {zscore:.2f} timeframe is {timeframe}\n realtime_ph_time:{realtime_ph_time}"
|
40 |
+
# print(message) # Print the message to the console as well
|
41 |
+
# engine.say(message)
|
42 |
+
# engine.runAndWait()
|
43 |
+
|
44 |
+
# Function to send a Telegram message
|
45 |
+
def send_telegram_message(symbol, signal, zscore, timeframe, realtime_ph_time):
|
46 |
+
try:
|
47 |
+
message = f"🚨 Alarm Triggered! \nSymbol: {symbol}\nSignal: {signal}\nZ-score: {zscore:.2f} \nTimeframe: {timeframe} \n realtime_ph_time:{realtime_ph_time}"
|
48 |
+
bot.sendMessage(CHAT_ID, message)
|
49 |
+
print(f"Telegram message sent: {message}")
|
50 |
+
except Exception as e:
|
51 |
+
print(f"Error sending Telegram message: {e}")
|
52 |
+
|
53 |
+
# def check_recent_zscore_and_alarm(json_file_path):
|
54 |
+
# global triggered_alarms # Access the global set of triggered alarms
|
55 |
+
# try:
|
56 |
+
# # Load the JSON data
|
57 |
+
# with open(json_file_path, "r") as file:
|
58 |
+
# data = json.load(file)
|
59 |
+
|
60 |
+
# # Get current UTC time and 1 hour ago in UTC
|
61 |
+
# current_utc_time = datetime.now(timezone.utc)
|
62 |
+
# one_hour_ago = current_utc_time - timedelta(hours=1)
|
63 |
+
|
64 |
+
# btcdom_triggered = False # Flag to track if BTCDOM/USDT alarm has been triggered
|
65 |
+
# btcdom_zscore = None # Variable to store the zscore for BTCDOM/USDT
|
66 |
+
|
67 |
+
# # Get the zscore for BTCDOM/USDT from the data
|
68 |
+
# for signal in data:
|
69 |
+
# if signal["symbol"] == "BTCDOM/USDT":
|
70 |
+
# btcdom_zscore = signal["zscore"]
|
71 |
+
# break
|
72 |
+
|
73 |
+
# for signal in data:
|
74 |
+
# # Parse signal date and time as UTC
|
75 |
+
# date_and_time = datetime.strptime(signal["date_and_time"], "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc)
|
76 |
+
# zscore = signal["zscore"]
|
77 |
+
# symbol = signal["symbol"]
|
78 |
+
# time_frame = signal["time_frame"]
|
79 |
+
# realtime_ph_time = signal["realtime_ph_time"]
|
80 |
+
|
81 |
+
# # Create a unique identifier for this alarm
|
82 |
+
# alarm_id = f"{symbol}_{date_and_time.isoformat()}_{zscore:.2f}"
|
83 |
+
|
84 |
+
# # Check if the signal is within the last 1 hour in UTC
|
85 |
+
# if one_hour_ago <= date_and_time <= current_utc_time:
|
86 |
+
# # If BTCDOM/USDT zscore is < -2 and the altcoin zscore is > +2
|
87 |
+
# if btcdom_zscore < -2 and zscore > 2 and alarm_id not in triggered_alarms:
|
88 |
+
# print(f"Strongly Sell Signal! {symbol} at {signal['date_and_time']} with zscore {zscore} time frame is {time_frame}, realtime_ph_time {realtime_ph_time}")
|
89 |
+
# play_alarm_sound()
|
90 |
+
# speak_zscore_signal(symbol, "Strongly Sell", zscore, time_frame, realtime_ph_time)
|
91 |
+
# send_telegram_message(symbol, "Strongly Sell", zscore, time_frame, realtime_ph_time)
|
92 |
+
# triggered_alarms.add(alarm_id)
|
93 |
+
|
94 |
+
# # If BTCDOM/USDT zscore is > +2 and the altcoin zscore is < -2
|
95 |
+
# elif btcdom_zscore > 2 and zscore < -2 and alarm_id not in triggered_alarms:
|
96 |
+
# print(f"Strongly Buy Signal! {symbol} at {signal['date_and_time']} with zscore {zscore} time frame is {time_frame}")
|
97 |
+
# play_alarm_sound()
|
98 |
+
# speak_zscore_signal(symbol, "Strongly Buy", zscore, time_frame, realtime_ph_time)
|
99 |
+
# send_telegram_message(symbol, "Strongly Buy", zscore, time_frame, realtime_ph_time)
|
100 |
+
# triggered_alarms.add(alarm_id)
|
101 |
+
|
102 |
+
# # Check for other conditions for Sell, Buy, Prepare for Sell, or Prepare for Buy
|
103 |
+
# elif zscore > 2 and alarm_id not in triggered_alarms: # Sell signal (zscore > +2)
|
104 |
+
# print(f"Sell Signal! {symbol} at {signal['date_and_time']} with zscore {zscore} time frame is {time_frame}")
|
105 |
+
# play_alarm_sound()
|
106 |
+
# speak_zscore_signal(symbol, "Sell", zscore, time_frame, realtime_ph_time)
|
107 |
+
# send_telegram_message(symbol, "Sell", zscore, time_frame, realtime_ph_time)
|
108 |
+
# triggered_alarms.add(alarm_id)
|
109 |
+
|
110 |
+
# elif zscore < -2 and alarm_id not in triggered_alarms: # Buy signal (zscore < -2)
|
111 |
+
# print(f"Buy Signal! {symbol} at {signal['date_and_time']} with zscore {zscore} time frame is {time_frame}")
|
112 |
+
# play_alarm_sound()
|
113 |
+
# speak_zscore_signal(symbol, "Buy", zscore, time_frame, realtime_ph_time)
|
114 |
+
# send_telegram_message(symbol, "Buy", zscore, time_frame, realtime_ph_time)
|
115 |
+
# triggered_alarms.add(alarm_id)
|
116 |
+
|
117 |
+
# elif 1.5 < zscore <= 2 and alarm_id not in triggered_alarms: # Prepare for Sell signal (0 < zscore <= 2)
|
118 |
+
# print(f"Prepare for Sell! {symbol} at {signal['date_and_time']} with zscore {zscore} time frame is {time_frame}")
|
119 |
+
# play_alarm_sound()
|
120 |
+
# speak_zscore_signal(symbol, "Prepare for Sell/HOLD", zscore, time_frame, realtime_ph_time)
|
121 |
+
# send_telegram_message(symbol, "Prepare for Sell/HOLD", zscore, time_frame, realtime_ph_time)
|
122 |
+
# triggered_alarms.add(alarm_id)
|
123 |
+
|
124 |
+
# elif -2 < zscore < -1.5 and alarm_id not in triggered_alarms: # Prepare for Buy signal (-2 < zscore < 0)
|
125 |
+
# print(f"Prepare for Buy! {symbol} at {signal['date_and_time']} with zscore {zscore} time frame is {time_frame}")
|
126 |
+
# play_alarm_sound()
|
127 |
+
# speak_zscore_signal(symbol, "Prepare for Buy/HOLD", zscore, time_frame, realtime_ph_time)
|
128 |
+
# send_telegram_message(symbol, "Prepare for Buy/HOLD", zscore, time_frame, realtime_ph_time)
|
129 |
+
# triggered_alarms.add(alarm_id)
|
130 |
+
|
131 |
+
# # Wait for 1 minute to avoid spamming
|
132 |
+
# time.sleep(60)
|
133 |
+
|
134 |
+
# except Exception as e:
|
135 |
+
# print(f"Error: {e}")
|
136 |
+
# State tracking for each symbol
|
137 |
+
zscore_states = {}
|
138 |
+
|
139 |
+
def save_data(symbol, zscore, time_frame, realtime_ph_time):
|
140 |
+
# Save the Z-score data to a file or database for review
|
141 |
+
with open("zscore_data_log.txt", "a") as file:
|
142 |
+
file.write(f"{datetime.now()}, {symbol}, {zscore}, {time_frame}, {realtime_ph_time}\n")
|
143 |
+
|
144 |
+
def check_recent_zscore_and_alarm(json_file_path):
|
145 |
+
global zscore_states # Access the global state tracking
|
146 |
+
try:
|
147 |
+
with open(json_file_path, "r") as file:
|
148 |
+
data = json.load(file)
|
149 |
+
|
150 |
+
current_utc_time = datetime.now(timezone.utc)
|
151 |
+
one_hour_ago = current_utc_time - timedelta(hours=1)
|
152 |
+
|
153 |
+
for signal in data:
|
154 |
+
# Parse signal details
|
155 |
+
symbol = signal["symbol"]
|
156 |
+
zscore = signal["zscore"]
|
157 |
+
date_and_time = datetime.strptime(signal["date_and_time"], "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc)
|
158 |
+
time_frame = signal["time_frame"]
|
159 |
+
realtime_ph_time = signal["realtime_ph_time"]
|
160 |
+
|
161 |
+
# Skip processing signals outside the 1-hour window
|
162 |
+
if not (one_hour_ago <= date_and_time <= current_utc_time):
|
163 |
+
continue
|
164 |
+
|
165 |
+
# Initialize state tracking for the symbol
|
166 |
+
if symbol not in zscore_states:
|
167 |
+
zscore_states[symbol] = {"was_low": False, "was_high": False}
|
168 |
+
|
169 |
+
# Determine if an alarm should be triggered
|
170 |
+
state = zscore_states[symbol]
|
171 |
+
|
172 |
+
# Save data if Z-score hits extreme values (-2 or 2)
|
173 |
+
if zscore == -2 or zscore == 2:
|
174 |
+
save_data(symbol, zscore, time_frame, realtime_ph_time)
|
175 |
+
print(f"Data saved for {symbol} at Z-score: {zscore}")
|
176 |
+
|
177 |
+
# Alarm conditions
|
178 |
+
if zscore < -2: # Z-score is very low (below -2, no alarm yet)
|
179 |
+
state["was_low"] = True
|
180 |
+
state["was_high"] = False
|
181 |
+
|
182 |
+
elif zscore > 2: # Z-score is very high (above 2, no alarm yet)
|
183 |
+
state["was_high"] = True
|
184 |
+
state["was_low"] = False
|
185 |
+
|
186 |
+
elif -1.85 <= zscore < -1: # Returning to mid-range from low extreme
|
187 |
+
if state["was_low"]: # Trigger only if it was previously low
|
188 |
+
print(f"Buy Alarm! {symbol} returning to range with Z-score {zscore}")
|
189 |
+
play_alarm_sound()
|
190 |
+
# speak_zscore_signal(symbol, "Buy Alarm", zscore, time_frame, realtime_ph_time)
|
191 |
+
send_telegram_message(symbol, "Buy Alarm", zscore, time_frame, realtime_ph_time)
|
192 |
+
state["was_low"] = False # Reset the state
|
193 |
+
|
194 |
+
elif 1 <= zscore <= 1.85: # Returning to mid-range from high extreme
|
195 |
+
if state["was_high"]: # Trigger only if it was previously high
|
196 |
+
print(f"Sell Alarm! {symbol} returning to range with Z-score {zscore}")
|
197 |
+
play_alarm_sound()
|
198 |
+
# speak_zscore_signal(symbol, "Sell Alarm", zscore, time_frame, realtime_ph_time)
|
199 |
+
send_telegram_message(symbol, "Sell Alarm", zscore, time_frame, realtime_ph_time)
|
200 |
+
state["was_high"] = False # Reset the state
|
201 |
+
|
202 |
+
# Wait for 1 minute to avoid spamming
|
203 |
+
time.sleep(60)
|
204 |
+
|
205 |
+
except Exception as e:
|
206 |
+
print(f"Error: {e}")
|
207 |
+
|
208 |
+
|
209 |
+
# Scheduler function to run every 3:55 to 4:10 and 7:55 to 8:10
|
210 |
+
def scheduled_task():
|
211 |
+
check_recent_zscore_and_alarm(json_file_path)
|
212 |
+
|
213 |
+
# Set up the scheduler
|
214 |
+
scheduler = BlockingScheduler()
|
215 |
+
trigger1 = CronTrigger(minute="55-59")
|
216 |
+
trigger2 = CronTrigger(minute="00-10")
|
217 |
+
# Define triggers
|
218 |
+
# trigger1 = CronTrigger(minute="55-59", hour="3,7,11,15,19,23")
|
219 |
+
# trigger2 = CronTrigger(minute="00-10", hour="4,8,12,16,20,0")
|
220 |
+
|
221 |
+
# Add the jobs to the scheduler
|
222 |
+
scheduler.add_job(scheduled_task, trigger1)
|
223 |
+
scheduler.add_job(scheduled_task, trigger2)
|
224 |
+
|
225 |
+
# Start the scheduler
|
226 |
+
scheduler.start()
|
app.py
DELETED
@@ -1,5 +0,0 @@
|
|
1 |
-
import time
|
2 |
-
|
3 |
-
while True:
|
4 |
-
print('hello world')
|
5 |
-
time.sleep(2)
|
|
|
|
|
|
|
|
|
|
|
|
atom_usdt_1h.png
ADDED
![]() |
atom_usdt_4h.png
ADDED
![]() |
image_coordinate.py
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
|
3 |
+
# Load your image
|
4 |
+
image = cv2.imread('/media/gjin/New Volume/BACKTEST_DATA/black_edition_rolling_window_50_candlestick_10/images_detection/4h/ADA_USDT_output_result_2024-10-09_16-00-00.jpg')
|
5 |
+
original_image = image.copy() # Keep a copy of the original image to reset after every frame
|
6 |
+
|
7 |
+
# Get the dimensions of the image
|
8 |
+
height, width, _ = image.shape
|
9 |
+
|
10 |
+
# Define the step size for the grid
|
11 |
+
step_x = 50 # Step size for x-axis
|
12 |
+
step_y = 50 # Step size for y-axis
|
13 |
+
|
14 |
+
# Draw grid lines
|
15 |
+
def draw_grid(img):
|
16 |
+
for x in range(0, width, step_x):
|
17 |
+
cv2.line(img, (x, 0), (x, height), (0, 255, 0), 1) # Draw green vertical lines
|
18 |
+
cv2.putText(img, str(x), (x + 5, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
|
19 |
+
|
20 |
+
for y in range(0, height, step_y):
|
21 |
+
cv2.line(img, (0, y), (width, y), (0, 255, 0), 1) # Draw green horizontal lines
|
22 |
+
cv2.putText(img, str(y), (5, y + 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
|
23 |
+
|
24 |
+
# Mouse callback function to display cursor details
|
25 |
+
def show_mouse_position(event, x, y, flags, param):
|
26 |
+
global image
|
27 |
+
if event == cv2.EVENT_MOUSEMOVE: # Track mouse movement
|
28 |
+
image = original_image.copy() # Reset to original image every frame
|
29 |
+
draw_grid(image)
|
30 |
+
|
31 |
+
# Get the BGR color of the pixel at the cursor position
|
32 |
+
b, g, r = image[y, x]
|
33 |
+
|
34 |
+
# Display the x, y coordinates and BGR color values on the image
|
35 |
+
info_text = f"X: {x}, Y: {y}, Color: B: {b}, G: {g}, R: {r}"
|
36 |
+
cv2.putText(image, info_text, (10, height - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1) # Text in black
|
37 |
+
|
38 |
+
# Create a window
|
39 |
+
cv2.namedWindow('Image with Grid and Coordinates', cv2.WND_PROP_FULLSCREEN)
|
40 |
+
cv2.setWindowProperty('Image with Grid and Coordinates', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
|
41 |
+
|
42 |
+
# Set the mouse callback function to track the cursor movement
|
43 |
+
cv2.setMouseCallback('Image with Grid and Coordinates', show_mouse_position)
|
44 |
+
|
45 |
+
# Draw initial grid
|
46 |
+
draw_grid(image)
|
47 |
+
|
48 |
+
# Display the image with grid and cursor details
|
49 |
+
while True:
|
50 |
+
cv2.imshow('Image with Grid and Coordinates', image)
|
51 |
+
if cv2.waitKey(20) & 0xFF == 27: # Press 'Esc' to exit
|
52 |
+
break
|
53 |
+
|
54 |
+
cv2.destroyAllWindows()
|
main_with_plot copy.py
ADDED
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import ccxt
|
3 |
+
import matplotlib.pyplot as plt
|
4 |
+
import matplotlib.dates as mdates
|
5 |
+
import json
|
6 |
+
from datetime import datetime, timedelta
|
7 |
+
import pytz
|
8 |
+
|
9 |
+
# Prompt for the symbol and time frame
|
10 |
+
symbols = input('Please input Symbol: ')
|
11 |
+
timeframe = input("Please input time frame: ")
|
12 |
+
|
13 |
+
# Initialize Binance Futures API
|
14 |
+
binance = ccxt.binance({
|
15 |
+
'options': {'defaultType': 'future'}, # Specify futures
|
16 |
+
})
|
17 |
+
|
18 |
+
# Function to fetch historical data and calculate Z-Score
|
19 |
+
def fetch_and_calculate_zscore(symbol, timeframe, since, limit=200, rolling_window=30):
|
20 |
+
data = binance.fetch_ohlcv(symbol, timeframe=timeframe, since=since, limit=limit)
|
21 |
+
df = pd.DataFrame(data, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
|
22 |
+
|
23 |
+
# Convert timestamp to UTC datetime format
|
24 |
+
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms', utc=True)
|
25 |
+
|
26 |
+
# Calculate rolling mean, std, and Z-Score
|
27 |
+
df['mean'] = df['close'].rolling(window=rolling_window).mean()
|
28 |
+
df['std'] = df['close'].rolling(window=rolling_window).std()
|
29 |
+
df['z_score'] = (df['close'] - df['mean']) / df['std']
|
30 |
+
|
31 |
+
# Initialize signal columns
|
32 |
+
df['buy_signal'] = 0
|
33 |
+
df['sell_signal'] = 0
|
34 |
+
|
35 |
+
# Variables to track thresholds
|
36 |
+
in_sell_signal = False
|
37 |
+
in_buy_signal = False
|
38 |
+
signal_triggered = False # Track if any signal was triggered
|
39 |
+
|
40 |
+
# Iterate through the dataframe to track signals
|
41 |
+
for i in range(1, len(df)):
|
42 |
+
current_z = df.loc[i, 'z_score']
|
43 |
+
previous_z = df.loc[i - 1, 'z_score']
|
44 |
+
|
45 |
+
# Handle Z-score crossing extreme thresholds for sell signal
|
46 |
+
if not in_sell_signal:
|
47 |
+
# Z-score crosses above 1.85 (potential sell signal)
|
48 |
+
if current_z > 1.85 and previous_z <= 1.85:
|
49 |
+
print(f"Sell signal candidate at index {i}, Z-score = {current_z}")
|
50 |
+
in_sell_signal = True
|
51 |
+
|
52 |
+
# Handle Z-score crossing extreme thresholds for buy signal
|
53 |
+
if not in_buy_signal:
|
54 |
+
# Z-score crosses below -1.85 (potential buy signal)
|
55 |
+
if current_z < -1.85 and previous_z >= -1.85:
|
56 |
+
print(f"Buy signal candidate at index {i}, Z-score = {current_z}")
|
57 |
+
in_buy_signal = True
|
58 |
+
|
59 |
+
# Keep the signal active if the Z-score remains within the range
|
60 |
+
if in_sell_signal:
|
61 |
+
# Sell signal is triggered between 1.85 and 1
|
62 |
+
if 1 <= current_z <= 1.85:
|
63 |
+
df.loc[i, 'sell_signal'] = 1 # Sell signal active
|
64 |
+
print(f"Sell signal active at index {i}, Z-score = {current_z}")
|
65 |
+
signal_triggered = True
|
66 |
+
# Exit sell signal if Z-score falls below 1
|
67 |
+
elif current_z < 1:
|
68 |
+
in_sell_signal = False
|
69 |
+
print(f"Sell signal exited at index {i}, Z-score = {current_z}")
|
70 |
+
|
71 |
+
if in_buy_signal:
|
72 |
+
# Buy signal is triggered between -1.85 and -1
|
73 |
+
if -1.85 <= current_z <= -1:
|
74 |
+
df.loc[i, 'buy_signal'] = 1 # Buy signal active
|
75 |
+
print(f"Buy signal active at index {i}, Z-score = {current_z}")
|
76 |
+
signal_triggered = True
|
77 |
+
# Exit buy signal if Z-score rises above -1
|
78 |
+
elif current_z > -1:
|
79 |
+
in_buy_signal = False
|
80 |
+
print(f"Buy signal exited at index {i}, Z-score = {current_z}")
|
81 |
+
|
82 |
+
return df
|
83 |
+
|
84 |
+
|
85 |
+
# Convert time to local timezone (Philippine Time)
|
86 |
+
utc_time = datetime.utcnow()
|
87 |
+
philippine_tz = pytz.timezone('Asia/Manila')
|
88 |
+
philippine_time = pytz.utc.localize(utc_time).astimezone(philippine_tz)
|
89 |
+
|
90 |
+
# Format the time in your preferred format
|
91 |
+
formatted_ph_time = philippine_time.strftime("%Y-%m-%d %H:%M:%S")
|
92 |
+
|
93 |
+
|
94 |
+
|
95 |
+
# Function to update signals in JSON with Z-Score (Appending to file)
|
96 |
+
def update_signal_json(symbol, df, json_data):
|
97 |
+
# Extract latest data point
|
98 |
+
latest_data = df.iloc[-1]
|
99 |
+
|
100 |
+
# Check if the latest Z-score has a signal
|
101 |
+
signal_status = "True" if latest_data['buy_signal'] == 1 or latest_data['sell_signal'] == 1 else "False"
|
102 |
+
|
103 |
+
# Prepare new entry with real-time Z-Score
|
104 |
+
signal_entry = {
|
105 |
+
"symbol": symbol,
|
106 |
+
"time_frame": timeframe,
|
107 |
+
"date_and_time": latest_data['timestamp'].strftime("%Y-%m-%d %H:%M:%S"),
|
108 |
+
"realtime_ph_time": formatted_ph_time, # Add the local Philippine time (UTC+8)
|
109 |
+
"current_price": latest_data['close'],
|
110 |
+
"zscore": latest_data['z_score'],
|
111 |
+
"detection": signal_status # Add signal status
|
112 |
+
}
|
113 |
+
|
114 |
+
# Append new data to the existing list in json_data
|
115 |
+
json_data.append(signal_entry)
|
116 |
+
|
117 |
+
return json_data
|
118 |
+
|
119 |
+
# Function to plot data
|
120 |
+
def plot_data(btcdom_df, pair_df, btc_df, ax):
|
121 |
+
ax.clear() # Clear previous plots
|
122 |
+
|
123 |
+
# Plot Z-Scores for all pairs
|
124 |
+
ax.plot(btcdom_df['timestamp'], btcdom_df['z_score'], label="BTCDOM/USDT Z-Score", color='blue', linestyle='-')
|
125 |
+
ax.plot(pair_df['timestamp'], pair_df['z_score'], label=f"{symbols}/USDT Z-Score", color='orange', linestyle='-')
|
126 |
+
ax.plot(btc_df['timestamp'], btc_df['z_score'], label="BTC/USDT Z-Score", color='gray', linestyle='-')
|
127 |
+
|
128 |
+
# Add thresholds
|
129 |
+
ax.axhline(y=2, color='red', linestyle='--', label='Overbought Threshold')
|
130 |
+
ax.axhline(y=-2, color='green', linestyle='--', label='Oversold Threshold')
|
131 |
+
|
132 |
+
# Plot Buy and Sell signals for BTCDOM/USDT
|
133 |
+
ax.scatter(btcdom_df[btcdom_df['buy_signal'] == 1]['timestamp'], btcdom_df[btcdom_df['buy_signal'] == 1]['z_score'],
|
134 |
+
marker='^', color='green', label='BTCDOM Buy Signal')
|
135 |
+
ax.scatter(btcdom_df[btcdom_df['sell_signal'] == 1]['timestamp'], btcdom_df[btcdom_df['sell_signal'] == 1]['z_score'],
|
136 |
+
marker='v', color='red', label='BTCDOM Sell Signal')
|
137 |
+
|
138 |
+
# Plot signals for the other pair
|
139 |
+
ax.scatter(pair_df[pair_df['buy_signal'] == 1]['timestamp'], pair_df[pair_df['buy_signal'] == 1]['z_score'],
|
140 |
+
marker='^', color='green', alpha=0.5, label=f"{symbols} Buy Signal")
|
141 |
+
ax.scatter(pair_df[pair_df['sell_signal'] == 1]['timestamp'], pair_df[pair_df['sell_signal'] == 1]['z_score'],
|
142 |
+
marker='v', color='red', alpha=0.5, label=f"{symbols} Sell Signal")
|
143 |
+
|
144 |
+
# Format plot
|
145 |
+
ax.set_title(f"Z-Scores Signals {timeframe} for {symbols}/USDT Futures", fontsize=16)
|
146 |
+
ax.set_xlabel("Time (UTC)", fontsize=12)
|
147 |
+
ax.set_ylabel("Z-Score", fontsize=12)
|
148 |
+
ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d %H:%M"))
|
149 |
+
ax.legend(loc="upper left")
|
150 |
+
ax.grid(True)
|
151 |
+
plt.xticks(rotation=45)
|
152 |
+
|
153 |
+
plt.draw() # Redraw the plot
|
154 |
+
plt.pause(0.1) # Pause to allow plot to update
|
155 |
+
|
156 |
+
# Function to run historical data processing
|
157 |
+
def run_historical():
|
158 |
+
json_data = []
|
159 |
+
try:
|
160 |
+
with open('signals.json', 'r') as file:
|
161 |
+
json_data = json.load(file)
|
162 |
+
except FileNotFoundError:
|
163 |
+
pass
|
164 |
+
|
165 |
+
fig, ax = plt.subplots(figsize=(14, 7))
|
166 |
+
|
167 |
+
# Set start and end dates for the loop
|
168 |
+
start_date = datetime(2023, 1, 1)
|
169 |
+
end_date = datetime(2024, 1, 1)
|
170 |
+
|
171 |
+
# Loop through each month in the date range (or week, depending on your choice)
|
172 |
+
current_date = start_date
|
173 |
+
while current_date < end_date:
|
174 |
+
# Set 'since' to the start of each month or week (whichever you prefer)
|
175 |
+
since = binance.parse8601(current_date.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
176 |
+
|
177 |
+
btcdom_symbol = 'BTCDOM/USDT'
|
178 |
+
pair_symbol = f'{symbols}/USDT'
|
179 |
+
btc_symbol = 'BTC/USDT'
|
180 |
+
|
181 |
+
# Fetch and process data
|
182 |
+
btcdom_df = fetch_and_calculate_zscore(btcdom_symbol, timeframe, since)
|
183 |
+
pair_df = fetch_and_calculate_zscore(pair_symbol, timeframe, since)
|
184 |
+
btc_df = fetch_and_calculate_zscore(btc_symbol, timeframe, since)
|
185 |
+
|
186 |
+
# Update signals and append to JSON
|
187 |
+
json_data = update_signal_json(pair_symbol, pair_df, json_data)
|
188 |
+
json_data = update_signal_json(btc_symbol, btc_df, json_data)
|
189 |
+
json_data = update_signal_json(btcdom_symbol, btcdom_df, json_data)
|
190 |
+
|
191 |
+
# Save updated signals to JSON
|
192 |
+
with open('signals.json', 'w') as file:
|
193 |
+
json.dump(json_data, file, indent=4)
|
194 |
+
|
195 |
+
# Plot the data
|
196 |
+
plot_data(btcdom_df, pair_df, btc_df, ax)
|
197 |
+
|
198 |
+
# Display the plot after each loop
|
199 |
+
plt.show() # Show the plot for the current iteration
|
200 |
+
|
201 |
+
# Move to the next chunk (next month/week)
|
202 |
+
current_date += timedelta(weeks=4)
|
203 |
+
|
204 |
+
# Run the historical data processing
|
205 |
+
run_historical()
|
main_with_plot.py
ADDED
@@ -0,0 +1,193 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import numpy as np
|
3 |
+
import ccxt
|
4 |
+
import matplotlib.pyplot as plt
|
5 |
+
import matplotlib.dates as mdates
|
6 |
+
import time
|
7 |
+
import json
|
8 |
+
from datetime import datetime
|
9 |
+
import pytz
|
10 |
+
|
11 |
+
# Prompt for the symbol
|
12 |
+
symbols = input('Please input Symbol: ')
|
13 |
+
timeframe = input("please input time frame: ")
|
14 |
+
# Initialize Binance Futures API
|
15 |
+
binance = ccxt.binance({
|
16 |
+
'options': {'defaultType': 'future'}, # Specify futures
|
17 |
+
})
|
18 |
+
def fetch_and_calculate_zscore(symbol, timeframe=timeframe, limit=200, rolling_window=30):
|
19 |
+
# Fetch OHLCV data
|
20 |
+
data = binance.fetch_ohlcv(symbol, timeframe=timeframe, limit=limit)
|
21 |
+
df = pd.DataFrame(data, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
|
22 |
+
# Convert timestamp to UTC datetime format
|
23 |
+
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms', utc=True)
|
24 |
+
|
25 |
+
# Calculate rolling mean, std, and Z-Score
|
26 |
+
df['mean'] = df['close'].rolling(window=rolling_window).mean()
|
27 |
+
df['std'] = df['close'].rolling(window=rolling_window).std()
|
28 |
+
df['z_score'] = (df['close'] - df['mean']) / df['std']
|
29 |
+
|
30 |
+
# Initialize signal columns
|
31 |
+
df['buy_signal'] = 0
|
32 |
+
df['sell_signal'] = 0
|
33 |
+
|
34 |
+
# Variables to track thresholds
|
35 |
+
in_sell_signal = False
|
36 |
+
in_buy_signal = False
|
37 |
+
signal_triggered = False # Track if any signal was triggered
|
38 |
+
|
39 |
+
# Iterate through the dataframe to track signals
|
40 |
+
for i in range(1, len(df)):
|
41 |
+
current_z = df.loc[i, 'z_score']
|
42 |
+
previous_z = df.loc[i - 1, 'z_score']
|
43 |
+
|
44 |
+
# Handle Z-score crossing extreme thresholds for sell signal
|
45 |
+
if not in_sell_signal:
|
46 |
+
# Z-score crosses above 1.85 (potential sell signal)
|
47 |
+
if current_z > 1.85 and previous_z <= 1.85:
|
48 |
+
#print(f"Sell signal candidate at index {i}, Z-score = {current_z}")
|
49 |
+
in_sell_signal = True
|
50 |
+
|
51 |
+
# Handle Z-score crossing extreme thresholds for buy signal
|
52 |
+
if not in_buy_signal:
|
53 |
+
# Z-score crosses below -1.85 (potential buy signal)
|
54 |
+
if current_z < -1.85 and previous_z >= -1.85:
|
55 |
+
#print(f"Buy signal candidate at index {i}, Z-score = {current_z}")
|
56 |
+
in_buy_signal = True
|
57 |
+
|
58 |
+
# Keep the signal active if the Z-score remains within the range
|
59 |
+
if in_sell_signal:
|
60 |
+
# Sell signal is triggered between 1.85 and 1
|
61 |
+
if 1 <= current_z <= 1.85:
|
62 |
+
df.loc[i, 'sell_signal'] = 1 # Sell signal active
|
63 |
+
#print(f"Sell signal active at index {i}, Z-score = {current_z}")
|
64 |
+
signal_triggered = True
|
65 |
+
# Exit sell signal if Z-score falls below 1
|
66 |
+
elif current_z < 1:
|
67 |
+
in_sell_signal = False
|
68 |
+
#print(f"Sell signal exited at index {i}, Z-score = {current_z}")
|
69 |
+
|
70 |
+
if in_buy_signal:
|
71 |
+
# Buy signal is triggered between -1.85 and -1
|
72 |
+
if -1.85 <= current_z <= -1:
|
73 |
+
df.loc[i, 'buy_signal'] = 1 # Buy signal active
|
74 |
+
#print(f"Buy signal active at index {i}, Z-score = {current_z}")
|
75 |
+
signal_triggered = True
|
76 |
+
# Exit buy signal if Z-score rises above -1
|
77 |
+
elif current_z > -1:
|
78 |
+
in_buy_signal = False
|
79 |
+
#print(f"Buy signal exited at index {i}, Z-score = {current_z}")
|
80 |
+
|
81 |
+
return df
|
82 |
+
|
83 |
+
|
84 |
+
|
85 |
+
utc_time = datetime.utcnow()
|
86 |
+
|
87 |
+
philippine_tz = pytz.timezone('Asia/Manila')
|
88 |
+
philippine_time = pytz.utc.localize(utc_time).astimezone(philippine_tz)
|
89 |
+
|
90 |
+
# Format the time in your preferred format
|
91 |
+
formatted_ph_time = philippine_time.strftime("%Y-%m-%d %H:%M:%S")
|
92 |
+
# Function to update signals in JSON
|
93 |
+
# Function to update signals in JSON with real-time Z-Score
|
94 |
+
def update_signal_json(symbol, df, json_data):
|
95 |
+
# Extract latest data point
|
96 |
+
latest_data = df.iloc[-1]
|
97 |
+
|
98 |
+
# Prepare new entry with real-time Z-Score
|
99 |
+
signal_entry = {
|
100 |
+
"symbol": symbol,
|
101 |
+
"time_frame": timeframe,
|
102 |
+
"date_and_time": latest_data['timestamp'].strftime("%Y-%m-%d %H:%M:%S"),
|
103 |
+
"realtime_ph_time": formatted_ph_time, # Add the local Philippine time (UTC+8)
|
104 |
+
"current_price": latest_data['close'],
|
105 |
+
"zscore": latest_data['z_score']
|
106 |
+
}
|
107 |
+
|
108 |
+
# Remove previous entries for this symbol
|
109 |
+
json_data = [entry for entry in json_data if entry['symbol'] != symbol]
|
110 |
+
|
111 |
+
# Add the latest entry
|
112 |
+
json_data.append(signal_entry)
|
113 |
+
|
114 |
+
return json_data
|
115 |
+
|
116 |
+
|
117 |
+
# Function to plot data
|
118 |
+
def plot_data(btcdom_df, pair_df, btc_df, ax):
|
119 |
+
ax.clear() # Clear previous plotspython /home/gjin/Documents/zscore/main_with_plot.py
|
120 |
+
|
121 |
+
# Plot Z-Scores for all pairs
|
122 |
+
ax.plot(btcdom_df['timestamp'], btcdom_df['z_score'], label="BTCDOM/USDT Z-Score", color='blue', linestyle='-')
|
123 |
+
ax.plot(pair_df['timestamp'], pair_df['z_score'], label=f"{symbols}/USDT Z-Score", color='orange', linestyle='-')
|
124 |
+
ax.plot(btc_df['timestamp'], btc_df['z_score'], label="BTC/USDT Z-Score", color='gray', linestyle='-')
|
125 |
+
|
126 |
+
# Add thresholds
|
127 |
+
ax.axhline(y=2, color='red', linestyle='--', label='Overbought Threshold')
|
128 |
+
ax.axhline(y=-2, color='green', linestyle='--', label='Oversold Threshold')
|
129 |
+
|
130 |
+
# Plot Buy and Sell signals for BTCDOM/USDT
|
131 |
+
ax.scatter(btcdom_df[btcdom_df['buy_signal'] == 1]['timestamp'], btcdom_df[btcdom_df['buy_signal'] == 1]['z_score'],
|
132 |
+
marker='^', color='green', label='BTCDOM Buy Signal')
|
133 |
+
ax.scatter(btcdom_df[btcdom_df['sell_signal'] == 1]['timestamp'], btcdom_df[btcdom_df['sell_signal'] == 1]['z_score'],
|
134 |
+
marker='v', color='red', label='BTCDOM Sell Signal')
|
135 |
+
|
136 |
+
# Plot signals for the other pair
|
137 |
+
ax.scatter(pair_df[pair_df['buy_signal'] == 1]['timestamp'], pair_df[pair_df['buy_signal'] == 1]['z_score'],
|
138 |
+
marker='^', color='green', alpha=0.5, label=f"{symbols} Buy Signal")
|
139 |
+
ax.scatter(pair_df[pair_df['sell_signal'] == 1]['timestamp'], pair_df[pair_df['sell_signal'] == 1]['z_score'],
|
140 |
+
marker='v', color='red', alpha=0.5, label=f"{symbols} Sell Signal")
|
141 |
+
|
142 |
+
# Format plot
|
143 |
+
ax.set_title(f"Z-Scores Signals {timeframe} for {symbols}/USDT Futures", fontsize=16)
|
144 |
+
ax.set_xlabel("Time (UTC)", fontsize=12)
|
145 |
+
ax.set_ylabel("Z-Score", fontsize=12)
|
146 |
+
ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d %H:%M"))
|
147 |
+
ax.legend(loc="upper left")
|
148 |
+
ax.grid(True)
|
149 |
+
plt.xticks(rotation=45)
|
150 |
+
|
151 |
+
# Real-time monitoring
|
152 |
+
# Real-time monitoring
|
153 |
+
def run_real_time():
|
154 |
+
json_data = []
|
155 |
+
try:
|
156 |
+
with open('signals.json', 'r') as file:
|
157 |
+
json_data = json.load(file)
|
158 |
+
except FileNotFoundError:
|
159 |
+
pass
|
160 |
+
|
161 |
+
fig, ax = plt.subplots(figsize=(14, 7))
|
162 |
+
plt.ion() # Interactive plotting
|
163 |
+
|
164 |
+
while True:
|
165 |
+
btcdom_symbol = 'BTCDOM/USDT'
|
166 |
+
pair_symbol = f'{symbols}/USDT'
|
167 |
+
btc_symbol = 'BTC/USDT'
|
168 |
+
|
169 |
+
btcdom_df = fetch_and_calculate_zscore(btcdom_symbol)
|
170 |
+
pair_df = fetch_and_calculate_zscore(pair_symbol)
|
171 |
+
btc_df = fetch_and_calculate_zscore(btc_symbol)
|
172 |
+
|
173 |
+
# Update JSON for BTCDOM
|
174 |
+
json_data = update_signal_json(btcdom_symbol, btcdom_df, json_data)
|
175 |
+
|
176 |
+
# Update JSON for selected pair
|
177 |
+
json_data = update_signal_json(pair_symbol, pair_df, json_data)
|
178 |
+
|
179 |
+
# Update JSON for BTC/USDT
|
180 |
+
json_data = update_signal_json(btc_symbol, btc_df, json_data)
|
181 |
+
|
182 |
+
# Save updated JSON
|
183 |
+
with open('signals.json', 'w') as file:
|
184 |
+
json.dump(json_data, file, indent=4)
|
185 |
+
|
186 |
+
# Update plot
|
187 |
+
plot_data(btcdom_df, pair_df, btc_df, ax)
|
188 |
+
plt.draw()
|
189 |
+
plt.pause(60) # Update every 60 seconds
|
190 |
+
time.sleep(60)
|
191 |
+
|
192 |
+
# Run the real-time system
|
193 |
+
run_real_time()
|
main_with_plot_image_send.py
ADDED
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import numpy as np
|
3 |
+
import ccxt
|
4 |
+
import matplotlib.pyplot as plt
|
5 |
+
import matplotlib.dates as mdates
|
6 |
+
import time
|
7 |
+
import json
|
8 |
+
from datetime import datetime
|
9 |
+
import pytz
|
10 |
+
import telepot
|
11 |
+
import os
|
12 |
+
|
13 |
+
# Constants
|
14 |
+
BOT_TOKEN = '6787349532:AAGSwuiEJeykI2rQgsoB8C_iXZYKYuJyoOM' # Replace with your bot token
|
15 |
+
CHAT_ID = '-4284060853' # Replace with your chat ID
|
16 |
+
|
17 |
+
bot = telepot.Bot(BOT_TOKEN)
|
18 |
+
|
19 |
+
# Prompt for the symbol
|
20 |
+
symbols = ['ADA/USDT', 'ATOM/USDT', 'XRP/USDT']
|
21 |
+
timeframes = ['1h', '4h']
|
22 |
+
|
23 |
+
# Directories to save images
|
24 |
+
base_directory = '../zscore'
|
25 |
+
image_directories = {
|
26 |
+
'1h': os.path.join(base_directory, 'images_1h'),
|
27 |
+
'4h': os.path.join(base_directory, 'images_4h')
|
28 |
+
}
|
29 |
+
for directory in image_directories.values():
|
30 |
+
os.makedirs(directory, exist_ok=True)
|
31 |
+
|
32 |
+
# Initialize Binance Futures API
|
33 |
+
binance = ccxt.binance({
|
34 |
+
'options': {'defaultType': 'future'}, # Specify futures
|
35 |
+
})
|
36 |
+
|
37 |
+
def fetch_and_calculate_zscore(symbol, timeframe, limit=200, rolling_window=30):
|
38 |
+
# Fetch OHLCV data
|
39 |
+
data = binance.fetch_ohlcv(symbol, timeframe=timeframe, limit=limit)
|
40 |
+
df = pd.DataFrame(data, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
|
41 |
+
# Convert timestamp to UTC datetime format
|
42 |
+
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms', utc=True)
|
43 |
+
|
44 |
+
# Calculate rolling mean, std, and Z-Score
|
45 |
+
df['mean'] = df['close'].rolling(window=rolling_window).mean()
|
46 |
+
df['std'] = df['close'].rolling(window=rolling_window).std()
|
47 |
+
df['z_score'] = (df['close'] - df['mean']) / df['std']
|
48 |
+
|
49 |
+
# Initialize signal columns
|
50 |
+
df['buy_signal'] = 0
|
51 |
+
df['sell_signal'] = 0
|
52 |
+
|
53 |
+
# Variables to track thresholds
|
54 |
+
in_sell_signal = False
|
55 |
+
in_buy_signal = False
|
56 |
+
signal_triggered = False # Track if any signal was triggered
|
57 |
+
|
58 |
+
# Iterate through the dataframe to track signals
|
59 |
+
for i in range(1, len(df)):
|
60 |
+
current_z = df.loc[i, 'z_score']
|
61 |
+
previous_z = df.loc[i - 1, 'z_score']
|
62 |
+
|
63 |
+
# Handle Z-score crossing extreme thresholds for sell signal
|
64 |
+
if not in_sell_signal:
|
65 |
+
if current_z > 1.85 and previous_z <= 1.85:
|
66 |
+
in_sell_signal = True
|
67 |
+
|
68 |
+
# Handle Z-score crossing extreme thresholds for buy signal
|
69 |
+
if not in_buy_signal:
|
70 |
+
if current_z < -1.85 and previous_z >= -1.85:
|
71 |
+
in_buy_signal = True
|
72 |
+
|
73 |
+
# Keep the signal active if the Z-score remains within the range
|
74 |
+
if in_sell_signal:
|
75 |
+
if 1 <= current_z <= 1.85:
|
76 |
+
df.loc[i, 'sell_signal'] = 1
|
77 |
+
signal_triggered = True
|
78 |
+
elif current_z < 1:
|
79 |
+
in_sell_signal = False
|
80 |
+
|
81 |
+
if in_buy_signal:
|
82 |
+
if -1.85 <= current_z <= -1:
|
83 |
+
df.loc[i, 'buy_signal'] = 1
|
84 |
+
signal_triggered = True
|
85 |
+
elif current_z > -1:
|
86 |
+
in_buy_signal = False
|
87 |
+
|
88 |
+
return df
|
89 |
+
|
90 |
+
utc_time = datetime.utcnow()
|
91 |
+
philippine_tz = pytz.timezone('Asia/Manila')
|
92 |
+
philippine_time = pytz.utc.localize(utc_time).astimezone(philippine_tz)
|
93 |
+
formatted_ph_time = philippine_time.strftime("%Y-%m-%d %H:%M:%S")
|
94 |
+
|
95 |
+
# Function to update signals in JSON with real-time Z-Score
|
96 |
+
def update_signal_json(symbol, df, timeframe, json_data):
|
97 |
+
latest_data = df.iloc[-1]
|
98 |
+
signal_entry = {
|
99 |
+
"symbol": symbol,
|
100 |
+
"time_frame": timeframe,
|
101 |
+
"date_and_time": latest_data['timestamp'].strftime("%Y-%m-%d %H:%M:%S"),
|
102 |
+
"realtime_ph_time": formatted_ph_time,
|
103 |
+
"current_price": latest_data['close'],
|
104 |
+
"zscore": latest_data['z_score']
|
105 |
+
}
|
106 |
+
json_data = [entry for entry in json_data if not (entry['symbol'] == symbol and entry['time_frame'] == timeframe)]
|
107 |
+
json_data.append(signal_entry)
|
108 |
+
return json_data
|
109 |
+
|
110 |
+
# Function to plot data for a single symbol including BTCDOM and BTC
|
111 |
+
def plot_data(pair_df, btcdom_df, btc_df, symbol, timeframe, ax):
|
112 |
+
ax.clear()
|
113 |
+
|
114 |
+
# Plot Z-Scores for all pairs
|
115 |
+
ax.plot(btcdom_df['timestamp'], btcdom_df['z_score'], label="BTCDOM/USDT Z-Score", color='blue', linestyle='-')
|
116 |
+
ax.plot(pair_df['timestamp'], pair_df['z_score'], label=f"{symbol} Z-Score", color='orange', linestyle='-')
|
117 |
+
ax.plot(btc_df['timestamp'], btc_df['z_score'], label="BTC/USDT Z-Score", color='gray', linestyle='-')
|
118 |
+
|
119 |
+
# Add thresholds
|
120 |
+
ax.axhline(y=2, color='red', linestyle='--', label='Overbought Threshold')
|
121 |
+
ax.axhline(y=-2, color='green', linestyle='--', label='Oversold Threshold')
|
122 |
+
|
123 |
+
# Plot Buy and Sell signals for the pair
|
124 |
+
ax.scatter(pair_df[pair_df['buy_signal'] == 1]['timestamp'], pair_df[pair_df['buy_signal'] == 1]['z_score'],
|
125 |
+
marker='^', color='green', label=f"{symbol} Buy Signal")
|
126 |
+
ax.scatter(pair_df[pair_df['sell_signal'] == 1]['timestamp'], pair_df[pair_df['sell_signal'] == 1]['z_score'],
|
127 |
+
marker='v', color='red', label=f"{symbol} Sell Signal")
|
128 |
+
|
129 |
+
# Format plot
|
130 |
+
ax.set_title(f"Z-Scores Signals {timeframe} for {symbol}", fontsize=16)
|
131 |
+
ax.set_xlabel("Time (UTC)", fontsize=12)
|
132 |
+
ax.set_ylabel("Z-Score", fontsize=12)
|
133 |
+
ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d %H:%M"))
|
134 |
+
ax.legend(loc="upper left")
|
135 |
+
ax.grid(True)
|
136 |
+
plt.xticks(rotation=45)
|
137 |
+
|
138 |
+
# Real-time monitoring
|
139 |
+
def run_real_time():
|
140 |
+
json_data = []
|
141 |
+
try:
|
142 |
+
with open('signals.json', 'r') as file:
|
143 |
+
json_data = json.load(file)
|
144 |
+
except FileNotFoundError:
|
145 |
+
pass
|
146 |
+
|
147 |
+
while True:
|
148 |
+
for timeframe in timeframes:
|
149 |
+
btcdom_symbol = 'BTCDOM/USDT'
|
150 |
+
btc_symbol = 'BTC/USDT'
|
151 |
+
btcdom_df = fetch_and_calculate_zscore(btcdom_symbol, timeframe)
|
152 |
+
btc_df = fetch_and_calculate_zscore(btc_symbol, timeframe)
|
153 |
+
|
154 |
+
# Send announcement message for the timeframe
|
155 |
+
message = f"{timeframe} time frame for {', '.join(symbols)}"
|
156 |
+
bot.sendMessage(chat_id=CHAT_ID, text=message)
|
157 |
+
|
158 |
+
media_group = []
|
159 |
+
for symbol in symbols:
|
160 |
+
pair_df = fetch_and_calculate_zscore(symbol, timeframe)
|
161 |
+
|
162 |
+
# Update JSON for the pair, BTCDOM, and BTC
|
163 |
+
json_data = update_signal_json(symbol, pair_df, timeframe, json_data)
|
164 |
+
json_data = update_signal_json(btcdom_symbol, btcdom_df, timeframe, json_data)
|
165 |
+
json_data = update_signal_json(btc_symbol, btc_df, timeframe, json_data)
|
166 |
+
|
167 |
+
# Create a new figure for each symbol and timeframe
|
168 |
+
fig, ax = plt.subplots(figsize=(14, 7))
|
169 |
+
plot_data(pair_df, btcdom_df, btc_df, symbol, timeframe, ax)
|
170 |
+
plt.tight_layout()
|
171 |
+
# Save image to the specified directory based on the timeframe
|
172 |
+
image_path = os.path.join(image_directories[timeframe], f"{symbol.lower().replace('/', '_')}_{timeframe}.png")
|
173 |
+
plt.savefig(image_path)
|
174 |
+
plt.close(fig) # Close the figure to free memory
|
175 |
+
|
176 |
+
# Add image to media group
|
177 |
+
media_group.append({'media': open(image_path, 'rb'), 'type': 'photo'})
|
178 |
+
|
179 |
+
# Send the media group to Telegram
|
180 |
+
try:
|
181 |
+
bot.sendMediaGroup(
|
182 |
+
chat_id=CHAT_ID,
|
183 |
+
media=media_group,
|
184 |
+
disable_notification=True
|
185 |
+
)
|
186 |
+
except Exception as e:
|
187 |
+
print(f"Failed to send media group for {timeframe} to Telegram: {e}")
|
188 |
+
|
189 |
+
# Save updated JSON for both timeframes
|
190 |
+
with open('signals.json', 'w') as file:
|
191 |
+
json.dump(json_data, file, indent=4)
|
192 |
+
|
193 |
+
time.sleep(60) # Wait for 60 seconds before next update
|
194 |
+
|
195 |
+
# Run the real-time system
|
196 |
+
run_real_time()
|
signals.json
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"symbol": "1000SHIB/USDT",
|
4 |
+
"time_frame": "1h",
|
5 |
+
"date_and_time": "2025-02-17 16:00:00",
|
6 |
+
"realtime_ph_time": "2025-02-18 00:54:17",
|
7 |
+
"current_price": 0.015581,
|
8 |
+
"zscore": -2.970455641927065
|
9 |
+
},
|
10 |
+
{
|
11 |
+
"symbol": "1000PEPE/USDT",
|
12 |
+
"time_frame": "1h",
|
13 |
+
"date_and_time": "2025-02-18 23:00:00",
|
14 |
+
"realtime_ph_time": "2025-02-19 00:31:52",
|
15 |
+
"current_price": 0.0092516,
|
16 |
+
"zscore": -0.848579839750643
|
17 |
+
},
|
18 |
+
{
|
19 |
+
"symbol": "ETH/USDT",
|
20 |
+
"time_frame": "1h",
|
21 |
+
"date_and_time": "2025-02-19 04:00:00",
|
22 |
+
"current_price": 2674.99,
|
23 |
+
"zscore": -0.09842164703262933,
|
24 |
+
"buy_signal": 0,
|
25 |
+
"sell_signal": 0
|
26 |
+
},
|
27 |
+
{
|
28 |
+
"symbol": "ETH/USDT",
|
29 |
+
"time_frame": "4h",
|
30 |
+
"date_and_time": "2025-02-19 04:00:00",
|
31 |
+
"current_price": 2675.0,
|
32 |
+
"zscore": -0.7886916975900665,
|
33 |
+
"buy_signal": 0,
|
34 |
+
"sell_signal": 0
|
35 |
+
},
|
36 |
+
{
|
37 |
+
"symbol": "DOGE/USDT",
|
38 |
+
"time_frame": "1h",
|
39 |
+
"date_and_time": "2025-02-19 04:00:00",
|
40 |
+
"current_price": 0.25039,
|
41 |
+
"zscore": -0.23689684021453575,
|
42 |
+
"buy_signal": 0,
|
43 |
+
"sell_signal": 0
|
44 |
+
},
|
45 |
+
{
|
46 |
+
"symbol": "DOGE/USDT",
|
47 |
+
"time_frame": "4h",
|
48 |
+
"date_and_time": "2025-02-19 04:00:00",
|
49 |
+
"current_price": 0.25038,
|
50 |
+
"zscore": -1.38866466036044,
|
51 |
+
"buy_signal": 1,
|
52 |
+
"sell_signal": 0
|
53 |
+
},
|
54 |
+
{
|
55 |
+
"symbol": "ADA/USDT",
|
56 |
+
"time_frame": "1h",
|
57 |
+
"date_and_time": "2025-02-19 05:00:00",
|
58 |
+
"realtime_ph_time": "2025-02-19 13:24:07",
|
59 |
+
"current_price": 0.736,
|
60 |
+
"zscore": -1.3425889423872113
|
61 |
+
},
|
62 |
+
{
|
63 |
+
"symbol": "ATOM/USDT",
|
64 |
+
"time_frame": "1h",
|
65 |
+
"date_and_time": "2025-02-19 05:00:00",
|
66 |
+
"realtime_ph_time": "2025-02-19 13:24:07",
|
67 |
+
"current_price": 4.508,
|
68 |
+
"zscore": -0.9086170027253152
|
69 |
+
},
|
70 |
+
{
|
71 |
+
"symbol": "XRP/USDT",
|
72 |
+
"time_frame": "1h",
|
73 |
+
"date_and_time": "2025-02-19 05:00:00",
|
74 |
+
"realtime_ph_time": "2025-02-19 13:24:07",
|
75 |
+
"current_price": 2.5169,
|
76 |
+
"zscore": -1.001519813480331
|
77 |
+
},
|
78 |
+
{
|
79 |
+
"symbol": "BTCDOM/USDT",
|
80 |
+
"time_frame": "1h",
|
81 |
+
"date_and_time": "2025-02-19 05:00:00",
|
82 |
+
"realtime_ph_time": "2025-02-19 13:24:07",
|
83 |
+
"current_price": 3746.0,
|
84 |
+
"zscore": 0.5070158300134885
|
85 |
+
},
|
86 |
+
{
|
87 |
+
"symbol": "BTC/USDT",
|
88 |
+
"time_frame": "1h",
|
89 |
+
"date_and_time": "2025-02-19 05:00:00",
|
90 |
+
"realtime_ph_time": "2025-02-19 13:24:07",
|
91 |
+
"current_price": 95045.5,
|
92 |
+
"zscore": -0.4977546948967619
|
93 |
+
},
|
94 |
+
{
|
95 |
+
"symbol": "ADA/USDT",
|
96 |
+
"time_frame": "4h",
|
97 |
+
"date_and_time": "2025-02-19 04:00:00",
|
98 |
+
"realtime_ph_time": "2025-02-19 13:24:07",
|
99 |
+
"current_price": 0.7357,
|
100 |
+
"zscore": -2.297588101404301
|
101 |
+
},
|
102 |
+
{
|
103 |
+
"symbol": "ATOM/USDT",
|
104 |
+
"time_frame": "4h",
|
105 |
+
"date_and_time": "2025-02-19 04:00:00",
|
106 |
+
"realtime_ph_time": "2025-02-19 13:24:07",
|
107 |
+
"current_price": 4.507,
|
108 |
+
"zscore": -1.8724272039451528
|
109 |
+
},
|
110 |
+
{
|
111 |
+
"symbol": "XRP/USDT",
|
112 |
+
"time_frame": "4h",
|
113 |
+
"date_and_time": "2025-02-19 04:00:00",
|
114 |
+
"realtime_ph_time": "2025-02-19 13:24:07",
|
115 |
+
"current_price": 2.5161,
|
116 |
+
"zscore": -1.8578167868901203
|
117 |
+
},
|
118 |
+
{
|
119 |
+
"symbol": "BTCDOM/USDT",
|
120 |
+
"time_frame": "4h",
|
121 |
+
"date_and_time": "2025-02-19 04:00:00",
|
122 |
+
"realtime_ph_time": "2025-02-19 13:24:07",
|
123 |
+
"current_price": 3747.3,
|
124 |
+
"zscore": 1.7310390668012654
|
125 |
+
},
|
126 |
+
{
|
127 |
+
"symbol": "BTC/USDT",
|
128 |
+
"time_frame": "4h",
|
129 |
+
"date_and_time": "2025-02-19 04:00:00",
|
130 |
+
"realtime_ph_time": "2025-02-19 13:24:07",
|
131 |
+
"current_price": 95040.0,
|
132 |
+
"zscore": -1.4683861167984986
|
133 |
+
}
|
134 |
+
]
|
xrp_usdt_1h.png
ADDED
![]() |
xrp_usdt_4h.png
ADDED
![]() |
yolo11n.pt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:0ebbc80d4a7680d14987a577cd21342b65ecfd94632bd9a8da63ae6417644ee1
|
3 |
+
size 5613764
|
zscore_backtest.py
ADDED
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import ccxt
|
3 |
+
import matplotlib.pyplot as plt
|
4 |
+
import matplotlib.dates as mdates
|
5 |
+
import json
|
6 |
+
from datetime import datetime, timedelta
|
7 |
+
import pytz
|
8 |
+
import os
|
9 |
+
images_folder = '/home/gjin/Documents/zscore/images'
|
10 |
+
os.makedirs(images_folder, exist_ok=True)
|
11 |
+
|
12 |
+
|
13 |
+
# Prompt for the symbol and time frame
|
14 |
+
symbols = input('Please input Symbol: ')
|
15 |
+
timeframe = input("Please input time frame: ")
|
16 |
+
|
17 |
+
# Initialize Binance Futures API
|
18 |
+
binance = ccxt.binance({
|
19 |
+
'options': {'defaultType': 'future'}, # Specify futures
|
20 |
+
})
|
21 |
+
|
22 |
+
|
23 |
+
|
24 |
+
from tqdm import tqdm
|
25 |
+
import pandas as pd
|
26 |
+
|
27 |
+
def fetch_and_calculate_zscore(symbol, timeframe, since, limit=200, rolling_window=30):
|
28 |
+
data = binance.fetch_ohlcv(symbol, timeframe=timeframe, since=since, limit=limit)
|
29 |
+
df = pd.DataFrame(data, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
|
30 |
+
|
31 |
+
# Convert timestamp to UTC datetime format
|
32 |
+
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms', utc=True)
|
33 |
+
|
34 |
+
# Calculate rolling mean, std, and Z-Score
|
35 |
+
df['mean'] = df['close'].rolling(window=rolling_window).mean()
|
36 |
+
df['std'] = df['close'].rolling(window=rolling_window).std()
|
37 |
+
df['z_score'] = (df['close'] - df['mean']) / df['std']
|
38 |
+
|
39 |
+
# Initialize signal columns
|
40 |
+
df['buy_signal'] = 0
|
41 |
+
df['sell_signal'] = 0
|
42 |
+
|
43 |
+
# Variables to track thresholds and state
|
44 |
+
in_sell_signal = False
|
45 |
+
in_buy_signal = False
|
46 |
+
crossed_threshold = False # Track if the extreme threshold has been crossed (2 or -2)
|
47 |
+
|
48 |
+
# Iterate through the dataframe to track signals with tqdm progress bar
|
49 |
+
for i in tqdm(range(1, len(df)), desc="Processing Z-score signals"):
|
50 |
+
current_z = df.loc[i, 'z_score']
|
51 |
+
|
52 |
+
# Track when Z-score crosses the thresholds (2 and -2)
|
53 |
+
if current_z > 2 and not crossed_threshold: # If Z-score exceeds 2
|
54 |
+
crossed_threshold = True
|
55 |
+
in_sell_signal = True # Trigger sell signal
|
56 |
+
|
57 |
+
elif current_z < -2 and not crossed_threshold: # If Z-score falls below -2
|
58 |
+
crossed_threshold = True
|
59 |
+
in_buy_signal = True # Trigger buy signal
|
60 |
+
|
61 |
+
# Maintain sell signal between 1 and 2
|
62 |
+
if in_sell_signal:
|
63 |
+
if 1 <= current_z <= 2:
|
64 |
+
df.loc[i, 'sell_signal'] = 1 # Sell signal active
|
65 |
+
# Exit sell signal if Z-score falls below 1
|
66 |
+
elif current_z < 1:
|
67 |
+
in_sell_signal = False
|
68 |
+
crossed_threshold = False # Reset threshold crossing
|
69 |
+
|
70 |
+
# Maintain buy signal between -2 and -1
|
71 |
+
if in_buy_signal:
|
72 |
+
if -2 <= current_z <= -1:
|
73 |
+
df.loc[i, 'buy_signal'] = 1 # Buy signal active
|
74 |
+
# Exit buy signal if Z-score rises above -1
|
75 |
+
elif current_z > -1:
|
76 |
+
in_buy_signal = False
|
77 |
+
crossed_threshold = False # Reset threshold crossing
|
78 |
+
|
79 |
+
return df
|
80 |
+
|
81 |
+
|
82 |
+
|
83 |
+
|
84 |
+
|
85 |
+
|
86 |
+
# Convert time to local timezone (Philippine Time)
|
87 |
+
utc_time = datetime.utcnow()
|
88 |
+
philippine_tz = pytz.timezone('Asia/Manila')
|
89 |
+
philippine_time = pytz.utc.localize(utc_time).astimezone(philippine_tz)
|
90 |
+
|
91 |
+
# Format the time in your preferred format
|
92 |
+
formatted_ph_time = philippine_time.strftime("%Y-%m-%d %H:%M:%S")
|
93 |
+
|
94 |
+
|
95 |
+
|
96 |
+
|
97 |
+
latest_data = []
|
98 |
+
def update_signal_json(symbol, df, json_data):
|
99 |
+
# Extract the latest data point from the DataFrame
|
100 |
+
global latest_data
|
101 |
+
latest_data = df.iloc[-1] # Update to get the last row
|
102 |
+
|
103 |
+
# Get the timestamp from the latest data and format it
|
104 |
+
timestamp = latest_data['timestamp'].strftime("%Y-%m-%d %H:%M:%S") if isinstance(latest_data['timestamp'], pd.Timestamp) else str(latest_data['timestamp'])
|
105 |
+
|
106 |
+
# Check if the latest Z-score has a signal
|
107 |
+
signal_status = "True" if latest_data['buy_signal'] == 1 or latest_data['sell_signal'] == 1 else "False"
|
108 |
+
|
109 |
+
# Prepare new entry with real-time Z-Score
|
110 |
+
signal_entry = {
|
111 |
+
"symbol": symbol,
|
112 |
+
"time_frame": timeframe, # Make sure `timeframe` is defined or passed to this function
|
113 |
+
"date_and_time": timestamp, # Correct timestamp for the entry
|
114 |
+
"realtime_ph_time": formatted_ph_time, # Add the local Philippine time (UTC+8)
|
115 |
+
"current_price": latest_data['close'], # Closing price for the most recent entry
|
116 |
+
"zscore": latest_data['z_score'], # Z-Score value
|
117 |
+
"detection": signal_status # Add signal status
|
118 |
+
}
|
119 |
+
|
120 |
+
# Append the new data to the json_data list
|
121 |
+
json_data.append(signal_entry)
|
122 |
+
|
123 |
+
return json_data
|
124 |
+
|
125 |
+
def plot_data(btcdom_df, pair_df, btc_df):
|
126 |
+
fig, ax = plt.subplots(figsize=(14, 7))
|
127 |
+
|
128 |
+
# Clear previous plots
|
129 |
+
ax.clear()
|
130 |
+
|
131 |
+
# Plot Z-Scores for all pairs
|
132 |
+
ax.plot(btcdom_df['timestamp'], btcdom_df['z_score'], label="BTCDOM/USDT Z-Score", color='blue', linestyle='-')
|
133 |
+
ax.plot(pair_df['timestamp'], pair_df['z_score'], label=f"{symbols}/USDT Z-Score", color='orange', linestyle='-')
|
134 |
+
ax.plot(btc_df['timestamp'], btc_df['z_score'], label="BTC/USDT Z-Score", color='gray', linestyle='-')
|
135 |
+
|
136 |
+
# Add thresholds
|
137 |
+
ax.axhline(y=2, color='red', linestyle='--', label='Overbought Threshold')
|
138 |
+
ax.axhline(y=-2, color='green', linestyle='--', label='Oversold Threshold')
|
139 |
+
|
140 |
+
# Plot Buy and Sell signals for BTCDOM/USDT
|
141 |
+
ax.scatter(btcdom_df[btcdom_df['buy_signal'] == 1]['timestamp'], btcdom_df[btcdom_df['buy_signal'] == 1]['z_score'],
|
142 |
+
marker='^', color='green', label='BTCDOM Buy Signal')
|
143 |
+
ax.scatter(btcdom_df[btcdom_df['sell_signal'] == 1]['timestamp'], btcdom_df[btcdom_df['sell_signal'] == 1]['z_score'],
|
144 |
+
marker='v', color='red', label='BTCDOM Sell Signal')
|
145 |
+
|
146 |
+
# Plot signals for the other pair
|
147 |
+
ax.scatter(pair_df[pair_df['buy_signal'] == 1]['timestamp'], pair_df[pair_df['buy_signal'] == 1]['z_score'],
|
148 |
+
marker='^', color='green', alpha=0.5, label=f"{symbols} Buy Signal")
|
149 |
+
ax.scatter(pair_df[pair_df['sell_signal'] == 1]['timestamp'], pair_df[pair_df['sell_signal'] == 1]['z_score'],
|
150 |
+
marker='v', color='red', alpha=0.5, label=f"{symbols} Sell Signal")
|
151 |
+
|
152 |
+
# Format plot
|
153 |
+
ax.set_title(f"Z-Scores Signals {timeframe} for {symbols}/USDT Futures", fontsize=16)
|
154 |
+
ax.set_xlabel("Time (UTC)", fontsize=12)
|
155 |
+
ax.set_ylabel("Z-Score", fontsize=12)
|
156 |
+
ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d %H:%M"))
|
157 |
+
ax.legend(loc="upper left")
|
158 |
+
ax.grid(True)
|
159 |
+
plt.xticks(rotation=45)
|
160 |
+
|
161 |
+
# Save each plot with unique filename
|
162 |
+
global latest_data
|
163 |
+
plot_filename = f"/home/gjin/Documents/zscore/images/zscore_plot_{symbols}_{latest_data['timestamp'].strftime('%Y%m%d_%H%M%S')}.png"
|
164 |
+
plt.savefig(plot_filename)
|
165 |
+
plt.close(fig) # Close the figure to prevent memory issues
|
166 |
+
|
167 |
+
# plt.close(fig) # Close the figure to prevent memory issues
|
168 |
+
|
169 |
+
# Function to run historical data processing
|
170 |
+
def run_historical():
|
171 |
+
json_data = []
|
172 |
+
try:
|
173 |
+
with open(f'signals_{symbols}.json', 'r') as file:
|
174 |
+
json_data = json.load(file)
|
175 |
+
except FileNotFoundError:
|
176 |
+
pass
|
177 |
+
|
178 |
+
# Set start and end dates for the loop
|
179 |
+
start_date = datetime(2024, 9, 1)
|
180 |
+
end_date = datetime(2024, 11, 27)
|
181 |
+
|
182 |
+
# Loop through each month in the date range (or week, depending on your choice)
|
183 |
+
current_date = start_date
|
184 |
+
while current_date < end_date:
|
185 |
+
# Set 'since' to the start of each month or week (whichever you prefer)
|
186 |
+
since = binance.parse8601(current_date.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
187 |
+
|
188 |
+
btcdom_symbol = 'BTCDOM/USDT'
|
189 |
+
pair_symbol = f'{symbols}/USDT'
|
190 |
+
btc_symbol = 'BTC/USDT'
|
191 |
+
|
192 |
+
# Fetch and process data
|
193 |
+
btcdom_df = fetch_and_calculate_zscore(btcdom_symbol, timeframe, since)
|
194 |
+
pair_df = fetch_and_calculate_zscore(pair_symbol, timeframe, since)
|
195 |
+
btc_df = fetch_and_calculate_zscore(btc_symbol, timeframe, since)
|
196 |
+
|
197 |
+
# Update signals and append to JSON
|
198 |
+
json_data = update_signal_json(pair_symbol, pair_df, json_data)
|
199 |
+
json_data = update_signal_json(btc_symbol, btc_df, json_data)
|
200 |
+
json_data = update_signal_json(btcdom_symbol, btcdom_df, json_data)
|
201 |
+
|
202 |
+
# Save updated signals to JSON
|
203 |
+
with open(f'signals{symbols}.json', 'w') as file:
|
204 |
+
json.dump(json_data, file, indent=4)
|
205 |
+
|
206 |
+
# Plot the data and save each plot separately
|
207 |
+
plot_data(btcdom_df, pair_df, btc_df)
|
208 |
+
|
209 |
+
# Move to the next chunk (next month/week)
|
210 |
+
current_date += timedelta(hours=4)
|
211 |
+
|
212 |
+
# Start historical data processing
|
213 |
+
run_historical()
|