Update README
This commit is contained in:
170
deploy_scripts/daily_market_update.py
Normal file
170
deploy_scripts/daily_market_update.py
Normal file
@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Daily Market Update — fetches live prices, generates SEO page, uploads to server.
|
||||
Usage:
|
||||
python daily_market_update.py # fetch + generate
|
||||
python daily_market_update.py --no-fetch # demo data
|
||||
python daily_market_update.py --upload # generate + upload to server
|
||||
python daily_market_update.py --schedule # print Windows Task Scheduler instructions
|
||||
"""
|
||||
|
||||
import os, sys, io, json, argparse, urllib.request, subprocess
|
||||
from datetime import datetime
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
OUTPUT_DIR = os.path.join(BASE_DIR, 'output')
|
||||
SITE_URL = 'https://blog.quant-view.xyz'
|
||||
|
||||
SYMBOLS = [
|
||||
('XAUUSD', 'Gold', 'XAU/USD'),
|
||||
('EURUSD', 'EUR/USD', 'EUR/USD'),
|
||||
('GBPUSD', 'GBP/USD', 'GBP/USD'),
|
||||
('BTCUSD', 'Bitcoin', 'BTC/USD'),
|
||||
('WTI', 'Crude Oil', 'WTI/CL'),
|
||||
]
|
||||
|
||||
def fetch_prices():
|
||||
prices = {}
|
||||
# Forex via exchangerate-api
|
||||
try:
|
||||
req = urllib.request.Request('https://open.er-api.com/v6/latest/USD',
|
||||
headers={'User-Agent': 'Mozilla/5.0'})
|
||||
data = json.loads(urllib.request.urlopen(req, timeout=10).read())
|
||||
r = data['rates']
|
||||
prices['EURUSD'] = 1 / r['EUR']
|
||||
prices['GBPUSD'] = 1 / r['GBP']
|
||||
except: pass
|
||||
|
||||
# BTC via CoinGecko
|
||||
try:
|
||||
req = urllib.request.Request('https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd',
|
||||
headers={'User-Agent': 'Mozilla/5.0'})
|
||||
data = json.loads(urllib.request.urlopen(req, timeout=10).read())
|
||||
prices['BTCUSD'] = data['bitcoin']['usd']
|
||||
except: pass
|
||||
|
||||
# Gold via GoldAPI (free tier)
|
||||
gold_key = os.environ.get('GOLD_API_KEY', '')
|
||||
if gold_key:
|
||||
try:
|
||||
req = urllib.request.Request('https://www.goldapi.io/api/XAU/USD',
|
||||
headers={'x-access-token': gold_key, 'User-Agent': 'Mozilla/5.0'})
|
||||
data = json.loads(urllib.request.urlopen(req, timeout=10).read())
|
||||
prices['XAUUSD'] = data.get('price')
|
||||
except: pass
|
||||
|
||||
return prices
|
||||
|
||||
def generate_html(prices):
|
||||
now = datetime.utcnow().strftime('%Y-%m-%d %H:%M UTC')
|
||||
rows = ''
|
||||
for key, label, pair in SYMBOLS:
|
||||
p = prices.get(key)
|
||||
price_str = f'${p:,.2f}' if p else '<span style="color:#666;">unavailable</span>'
|
||||
rows += f'<tr><td style="padding:10px 12px;border-bottom:1px solid #222;">{label}</td>'
|
||||
rows += f'<td style="padding:10px 12px;border-bottom:1px solid #222;text-align:right;font-family:monospace;">{price_str}</td>'
|
||||
rows += f'<td style="padding:10px 12px;border-bottom:1px solid #222;text-align:center;">—</td></tr>\n'
|
||||
|
||||
html = f'''<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>Daily Market Update {now[:10]} — Gold, Forex, Bitcoin | GFIL Trading Insights</title>
|
||||
<meta name="description" content="Live market prices for XAUUSD, EUR/USD, GBP/USD, Bitcoin and WTI Crude Oil. Updated {now}.">
|
||||
<meta name="robots" content="index, follow">
|
||||
<link rel="canonical" href="{SITE_URL}/market-update.html">
|
||||
<style>
|
||||
*{{margin:0;padding:0;box-sizing:border-box;}}
|
||||
body{{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0a0a0f;color:#e0e0e0;max-width:800px;margin:0 auto;padding:20px;}}
|
||||
h1{{color:#ffcc00;border-bottom:1px solid #333;padding-bottom:10px;font-size:24px;}}
|
||||
.subtitle{{color:#888;font-size:13px;margin:10px 0 20px;}}
|
||||
table{{width:100%;border-collapse:collapse;}}
|
||||
th{{text-align:left;padding:10px 12px;border-bottom:2px solid #ffcc00;color:#ffcc00;font-size:12px;text-transform:uppercase;}}
|
||||
td{{font-size:14px;}}
|
||||
tr:hover{{background:#0f0f15;}}
|
||||
.note{{color:#666;font-size:12px;margin-top:15px;}}
|
||||
.cta{{background:#111;border:1px solid #333;border-radius:8px;padding:20px;margin:25px 0;text-align:center;}}
|
||||
.cta a{{color:#ffcc00;font-weight:bold;text-decoration:none;}}
|
||||
.footer{{margin-top:30px;padding-top:15px;border-top:1px solid #333;text-align:center;color:#555;font-size:12px;}}
|
||||
.footer a{{color:#ffcc00;text-decoration:none;}}
|
||||
</style></head>
|
||||
<body>
|
||||
<h1>Daily Market Update</h1>
|
||||
<p class="subtitle">{now}</p>
|
||||
<table><thead><tr><th>Instrument</th><th style="text-align:right;">Price</th><th style="text-align:center;">Signal</th></tr></thead>
|
||||
<tbody>{rows}</tbody></table>
|
||||
<p class="note">Data from public APIs. For institutional-grade real-time data visit <a href="http://gold-node.xyz/" style="color:#ffcc00;">GFIL BOSS PANEL</a>.</p>
|
||||
<div class="cta"><p><a href="http://gold-node.xyz/">Access GFIL Terminal →</a> | <a href="https://t.me/GFIL_Trading">Telegram</a> | <a href="/">Blog Home</a></p></div>
|
||||
<div class="footer"><p>© {datetime.now().year} GFIL Trading Insights | <a href="/">Home</a> | <a href="https://t.me/GFIL_Trading">Telegram</a></p></div>
|
||||
</body></html>'''
|
||||
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
path = os.path.join(OUTPUT_DIR, 'market-update.html')
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
f.write(html)
|
||||
print(f'[ok] market-update.html ({len(html)} bytes)')
|
||||
return path
|
||||
|
||||
def upload():
|
||||
try:
|
||||
import paramiko, socket, time
|
||||
HOST = os.environ.get('GFIL_SSH_HOST', '')
|
||||
PASS = os.environ.get('GFIL_SSH_PASS', '')
|
||||
PROXY = os.environ.get('GFIL_HTTP_PROXY', '127.0.0.1:7890')
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(30)
|
||||
sock.connect(tuple(PROXY.split(':')))
|
||||
sock.sendall(f'CONNECT {HOST}:22 HTTP/1.1\r\nHost: {HOST}:22\r\n\r\n'.encode())
|
||||
resp = b''
|
||||
while b'\r\n\r\n' not in resp:
|
||||
resp += sock.recv(4096)
|
||||
if b'200' not in resp:
|
||||
raise Exception('proxy failed')
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect(HOST, port=22, username='root', password=PASS, sock=sock, timeout=30, banner_timeout=120)
|
||||
sftp = ssh.open_sftp()
|
||||
sftp.put(os.path.join(OUTPUT_DIR, 'market-update.html'), '/var/www/blog/market-update.html')
|
||||
sftp.close(); ssh.close(); sock.close()
|
||||
print('[ok] uploaded to server')
|
||||
except Exception as e:
|
||||
print(f'[warn] upload failed: {e}')
|
||||
|
||||
def print_schedule():
|
||||
print('''
|
||||
=== Windows Task Scheduler Setup ===
|
||||
1. Open Task Scheduler
|
||||
2. Create Basic Task → "GFIL Market Update"
|
||||
3. Trigger: Daily, repeat every 1 hour
|
||||
4. Action: Start a program
|
||||
Program: python
|
||||
Arguments: D:\\GFIL_BLOG\\deploy_scripts\\daily_market_update.py --upload
|
||||
Start in: D:\\GFIL_BLOG
|
||||
''')
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--no-fetch', action='store_true')
|
||||
parser.add_argument('--upload', action='store_true')
|
||||
parser.add_argument('--schedule', action='store_true')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.schedule:
|
||||
print_schedule()
|
||||
sys.exit(0)
|
||||
|
||||
print('=== Daily Market Update ===')
|
||||
if args.no_fetch:
|
||||
prices = {'XAUUSD': 2350.45, 'EURUSD': 1.0825, 'GBPUSD': 1.2734, 'BTCUSD': 87650.00}
|
||||
print('[demo mode]')
|
||||
else:
|
||||
prices = fetch_prices()
|
||||
print(f'fetched {len(prices)} symbols')
|
||||
|
||||
generate_html(prices)
|
||||
|
||||
if args.upload:
|
||||
upload()
|
||||
|
||||
print('=== done ===')
|
||||
Reference in New Issue
Block a user