#!/usr/bin/env python3
"""SEEDS MACD Bot - MACD crossover signals"""
import time,json,os,sys,logging
from datetime import datetime
logging.basicConfig(level=logging.INFO,format='%(asctime)s [%(levelname)s] %(message)s',handlers=[logging.StreamHandler()])
log=logging.getLogger(__name__)
BOT_DIR=os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0,BOT_DIR)
TRADE_FILE=os.path.join(BOT_DIR,'macd_trades.json')
CTRL_FILE=os.path.join(BOT_DIR,'bot_control.json')
COINS=[{'pair':'XETHZUSD','coin':'ETH','capital':30.0},{'pair':'SOLUSD','coin':'SOL','capital':30.0},{'pair':'XXBTZUSD','coin':'BTC','capital':30.0}]
FAST=12;SLOW=26;SIGNAL=9;TAKE_PROFIT=0.04;STOP_LOSS=0.02;INTERVAL=60
def ema(prices,period):
    if len(prices)<period: return None
    k=2/(period+1);e=sum(prices[:period])/period
    for p in prices[period:]: e=p*k+e*(1-k)
    return e
def calc_macd(prices):
    if len(prices)<SLOW+SIGNAL: return None,None,None
    fast=ema(prices,FAST);slow=ema(prices,SLOW)
    if not fast or not slow: return None,None,None
    macd=fast-slow
    vals=[]
    for i in range(SIGNAL+5,0,-1):
        s=prices[:-i] if i>0 else prices
        if len(s)>=SLOW:
            f=ema(s,FAST);sl=ema(s,SLOW)
            if f and sl: vals.append(f-sl)
    if len(vals)<SIGNAL: return macd,None,None
    sig=ema(vals,SIGNAL)
    return macd,sig,(macd-sig if sig else None)
def load_state():
    try:
        if os.path.exists(TRADE_FILE):
            with open(TRADE_FILE) as f: return json.load(f)
    except: pass
    return {'trades':[],'total_profit':0.0,'positions':{}}
def save_state(s): open(TRADE_FILE,'w').write(json.dumps(s,indent=2))
def is_enabled():
    try:
        if os.path.exists(CTRL_FILE):
            with open(CTRL_FILE) as f: return json.load(f).get('macd_enabled',True)
    except: pass
    return True
class MACDBot:
    def __init__(self,cfg,api):
        self.pair=cfg['pair'];self.coin=cfg['coin'];self.capital=cfg['capital']
        self.api=api;self.prices=[];self.position=None;self.buy_price=0.0;self.volume=0.0;self.prev_hist=None
    def get_price(self):
        try:
            r=self.api.query_public('Ticker',{'pair':self.pair})
            if not r.get('error'): return float(list(r['result'].values())[0]['c'][0])
        except: pass
        return None
    def update(self,state):
        price=self.get_price()
        if not price: return
        self.prices.append(price)
        if len(self.prices)>100: self.prices=self.prices[-100:]
        macd,sig,hist=calc_macd(self.prices)
        if macd is None: log.info(f'[{self.coin}] ${price:.4f} | Building MACD ({len(self.prices)}/{SLOW+SIGNAL})'); return
        log.info(f'[{self.coin}] ${price:.4f} | MACD:{macd:.4f} Signal:{sig:.4f} Hist:{hist:.4f}')
        if self.position=='long':
            pnl=(price-self.buy_price)/self.buy_price
            log.info(f'[{self.coin}] P&L: {pnl*100:.2f}%')
            bear=self.prev_hist and self.prev_hist>0 and hist<0
            if bear or pnl>=TAKE_PROFIT or pnl<=-STOP_LOSS:
                reason='macd_cross' if bear else ('take_profit' if pnl>=TAKE_PROFIT else 'stop_loss')
                self._sell(price,reason,state)
        elif self.position is None:
            bull=self.prev_hist and self.prev_hist<0 and hist>0
            if bull: self._buy(price,state)
        self.prev_hist=hist
    def _buy(self,price,state):
        try:
            vol=round(self.capital/price,6)
            r=self.api.query_private('AddOrder',{'pair':self.pair,'type':'buy','ordertype':'market','volume':str(vol)})
            if r.get('error'): log.warning(f'Buy error: {r["error"]}'); return
            self.position='long';self.buy_price=price;self.volume=vol
            state['positions'][self.coin]={'active':True,'buy_price':price,'volume':vol,'time':datetime.now().isoformat()}
            save_state(state);log.info(f'[{self.coin}] MACD BUY @ ${price:.4f}')
        except Exception as e: log.error(f'Error: {e}')
    def _sell(self,price,reason,state):
        try:
            r=self.api.query_private('AddOrder',{'pair':self.pair,'type':'sell','ordertype':'market','volume':str(self.volume)})
            if r.get('error'): log.warning(f'Sell error: {r["error"]}'); return
            net=(price-self.buy_price)*self.volume-(self.buy_price+price)*self.volume*0.0013
            state['total_profit']=round(state.get('total_profit',0)+net,4)
            state['trades'].append({'coin':self.coin,'buy_price':self.buy_price,'sell_price':price,'profit_usd':round(net,4),'reason':reason,'time':datetime.now().isoformat()})
            state['positions'][self.coin]={'active':False};save_state(state)
            self.position=None;log.info(f'[{self.coin}] MACD SELL @ ${price:.4f} | {reason} | Net: ${net:.4f}')
        except Exception as e: log.error(f'Error: {e}')
def main():
    import krakenex
    from config_advanced import API_KEY,API_SECRET
    api=krakenex.API(key=API_KEY,secret=API_SECRET)
    state=load_state();bots=[MACDBot(cfg,api) for cfg in COINS]
    for bot in bots:
        pos=state.get('positions',{}).get(bot.coin,{})
        if pos.get('active'): bot.position='long';bot.buy_price=pos.get('buy_price',0);bot.volume=pos.get('volume',0)
    log.info('='*60);log.info('SEEDS MACD Bot | LIVE');log.info('='*60)
    cycle=0
    while True:
        try:
            if not is_enabled(): log.info('[MACD] Disabled');time.sleep(60);continue
            cycle+=1;log.info(f'--- MACD Cycle {cycle} | {datetime.now().strftime("%Y-%m-%d %H:%M:%S")} ---')
            for bot in bots: bot.update(state);time.sleep(2)
            log.info(f'SUMMARY | P&L: ${state["total_profit"]:.4f} | Trades: {len(state["trades"])}')
            time.sleep(INTERVAL)
        except KeyboardInterrupt: break
        except Exception as e: log.error(f'Error: {e}');time.sleep(15)
if __name__=='__main__': main()
