Bot V5 ENHANCED: Risk Management Implementation

- Stop Loss: 2.5% on all trades
- Take Profit: 3% (increased from 1%)
- Daily Loss Limit: -5% max per day
- Risk/Reward: 1:1.2 ratio enforced
- All 5 current trades protected
- Deployment: Safe restart without trade interruption
This commit is contained in:
Marc Blatter 2026-07-04 22:59:33 +02:00
parent 400740b541
commit 7a6c888db4
3 changed files with 318 additions and 148 deletions

View File

@ -0,0 +1,24 @@
# Trading Bot V5 - Strategieanalyse
**Generiert:** 2026-07-04 22:45 UTC
**Status:** 🟢 Live Analysis
## Zusammenfassung
### Aktuelles Modell
- **Strategy:** Zufällige 5% Signal + Market Buy + +1% TP
- **Position Sizing:** 25% des USDT pro Trade
- **Risk Management:** KEINER (kein Stop Loss!)
- **Expected Win Rate:** 45% (unter Break Even)
- **Prognose:** 70% Wah...[truncated]
git add -A
git commit -m 'Add Trading Strategy PDF analysis + recommendations for optimization'
git push
echo ''
echo '✅ COMMITTED & PUSHED'
git log --oneline -2

View File

@ -0,0 +1,99 @@
%PDF-1.4
%“Œ‹ž ReportLab Generated PDF document (opensource)
1 0 obj
<<
/F1 2 0 R /F2 3 0 R /F3 4 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
>>
endobj
4 0 obj
<<
/BaseFont /ZapfDingbats /Name /F3 /Subtype /Type1 /Type /Font
>>
endobj
5 0 obj
<<
/Contents 10 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 9 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/Contents 11 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 9 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
7 0 obj
<<
/PageMode /UseNone /Pages 9 0 R /Type /Catalog
>>
endobj
8 0 obj
<<
/Author (\(anonymous\)) /CreationDate (D:20260704224531+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260704224531+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
>>
endobj
9 0 obj
<<
/Count 2 /Kids [ 5 0 R 6 0 R ] /Type /Pages
>>
endobj
10 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1766
>>
stream
GatU3>?BQ=&:Vs/Qj7q4g0M(OAGNNLUeN!9P*!1q:Cf**.)CmQ;q\$YJ,PCTaj#!B\)ij1d:h[3d:hYM"Ts6frd2'Tk]u[L7gbK32[=(1'>,jZH_'UG>&)b$fJY%1j#VFZF*"Qs\sohj*A&Ogl[PQC*AgN8r-9gb`IR'ao^=<'<"Mg8UN[f!Qga<bUUT00Wu^JW2`^ah(nO*5jM@t>Q+V<[\o/%Q\>d<@57:OlE%0+3j5cf0WU`uu#it5QjG3%h_YfGKV?6RV8ejo74f,tEO=H/('s&`%Q:m(fS5IJ`DZ(Z5PX,7;cE]9OQ8$Qa.poD_ThppbLSIr0n91uIlIlZVi=ZO)m!us_hfT2^W,&*h_.S$[R+2LJ'dnsqD%T9EG")t3Psr.qSS\u,JoGjgh.rFY@(?rhN[!L1@A]u&^IXXX-rM)G6/o,9/IP7@l]5P@cJpU7>HBWI#[/[LR$?7)=]7;u0G.$^31A/>(5&O_#FVr$`loC'3ZslVCdB$fMMoL.o@'ec)E3Jo79'tJ0=.-\[%Hh?>[`KUf[FF%$3,M@&5h<J_<9l![sqBMYU])XQQ]%DWNd$RHST*3<,FRa`]C)p\?)L]g.63d8[/UQ.4tuWFUE'`ZS[#-Is]$FD/W3hnQTpm&NF!lR1)Fh(Ol!!_^)3B`j'\po%hp,kK'p8VrG^:J,'OS%gf9\=C<L[@(Du'+HHFb\Ebbpc*0^+Af(^[$/uDaAP%-e/M#3r,i!MG9]\#sZk7[k0>f?OH^bu%BX]V+r?t\3](p,K/S,:&C^p+oJ-&Nqq*FX(PB8+GZu1O?Y%Oa)B"GMHPt^--oRdBE.P>%),G:Br_3F+9jlomdo,r`OkSoK,cdI&la[p**c&n"a5UCPG4n$&gnL%Yr7Br5?Y)5YdfIIa;9ZDD+AG+Z+JL=h#=:AWo\1"rkihLdd)FQBolQ?O8fa:466)qMm'3kr9hI&0&]0^;H+S):qCc4.Fj!V?oPD3a(qh&=,Jd/mXBcMhBfZ^qT<*Sb<f&suBhg8+g5hS`LE>%L#Q;RN-j4I3$-tDt5!LgJ-"/0^,f[%l!f;MI&l;qU9p1BeG>BFk5c-8DA;Q;*2WHXQ/>LXWL-RuP%;8QE=1YFN$Cn$f.UL+ra9bS.Xe9-oH'cr7lDmo)f":^]d"u3(@(e+mNgEH:1l3[H(&]8J7Ai`P"@iDsonD%Ih_)e(]?bXlsBM2'PE5mi;[#R`Q7eai0KXF9M@4daO_<P';U22L'TU)%6=MnNaCLT#\>E3/If5_.D27'.YEO7X+(eWKONhJ$^&M;Fnp;BiQlq7"?+F%Y7L:,N['l-\,]03\7<=io3MYQ*`9h1l1"T+<0$Pq(Yf.*F*jtH6Sh4.MWZdJ)%AsH""RFP?=g2B%@DT2%p6G_Z%BoRo0dM`Y>V)9;p\?!9qD@%OpCf+"Sa_&B9o$qo=M;j'bXJ?<TN="H"CD]/("m.1ENCdLj,f)80M_B7o7NQEECUSMQY19NIp+,Pp2ntjk]YX7=73BOALR2?IE+!Hth)gMmn\@Ea;?d^Q)>)rKQ-m?4:/VlX^>n"7E%;Y95GWr%,ECN"Kc9'SD0PVLl3!Kd<TCW@6QmbWCe'!a/CJt^>l%5^lA,B;]q<!tArj\BoMRTo(Q;NaP%pST;a"Zd56@6dp<Z@LgDsV=O3#Kk=V.,>,uODK)fOYms/=9Tq@/)1j&.)YoO<dD\HmE>UrHT1j=HQ,E9i9^6Qj;Gq3a1O73_G&,)eO&@134!Q(;DM&Vf=U64PF^FT)A",q+Z~>endstream
endobj
11 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1266
>>
stream
GatU1?#S^`&:O#NQkuRjDP;_/I-KogL!g_gZn+ULBpBJN9^p$+=keM9&,3QjEKV)0g?qSfZkYRoS2iB<Na8UDj(A>S#s^.so.(X4#)#WgrL+8U#R980cP*e?fkTQN>AL]0D*3A&ls_R9ljp&i"=(F[5m%B+%+kR3b6#+h3%(Z@+PA=-MGlh"DIZecW(KKP`@6K?6MQn$r.`N:fYDDG^qRX!fZ6XMp*dt^>J,:UW#1l6@O^3oj?WU5`A2h3%`@8,IfkfhP=qk`Y[kXc6A<5iWJF<]`C[NuBsVs;)B8p&Ak$ZG,di@A'@5nunle3i4?i0uUZti%'o"1T#c!u!UY))KgToIkEpP7(lglR]&[d-<0hdn.NgX!GD5bh>G26>0$&tTT3J28P?6qYg"*eC-9>^I&T)AqaA)<&<*haKO@"L7>9$S]Z/KlD05-A7Qqiu2\gK+g:1AO["-;lY\,@JN_R>=.jq$P3sUj*FYFO,Ud9S&!/dCR\_7C.JjT\o23rNLbb%^3,u6NM)4!V^WKqQS5\4)JT7+<8+lKJW4!-M/Ng'$apJ.O6c=2@LlrU-o;\O"*lKo)T:JEa(,_cA&iA9=`'\rb9pADG/NKUe>b5IqO*KY7?]Xq%$H<]K0kC(1hm@^Vj;c'.*'t4B$R5W@'^H9^mIkL]r6%`LQ5lVIl7eKJ3R2Eh2JNh:km0-3G<jY`PCR9\G#L4^k>^_YtF5p<=K!mRE!-[`U#YPT*X4=[JI4,d[sp,UeCp@YuL[!B46LU$s;QpC3&.<;oi@UPmmmX6FSX13lq8m2CWbkJd-N)uANOA(\mcBPjXO[reOo#?uSRiJMV:o9$AV<YH;P#8XaG@HgfLZ!k`O9ip.36=E0[%n+kM$m'CBU!KR4q4.41fMNgYKF9\F)2P7hEk+<^Q]"mEP2TLqE5'+1%?]?!V`*>o]\;l&/&0R/UPf/l2GiTaYspO+"VU\`&^TonF<A#as64si>SNKu?arVO'_O,C>YuTeIl9#7*n5oDHo/X[ah><a-s;2iD.sOdNuL,=fWjmuVg.WQE.&<.^E3tLdqk!Z.Lk>rY<:@fh,_2jM!#SgoRW=!0f)(%Y>g)(;"rB;o/lWSW!#DoM-*<#1MrMNYC8ds9>)*?h+DS^<kCm!-`B.>a9)oA5)`d#Y;Qq:Ob+F1!ehojRa'K64LQm5a:_r&s&,!86LI5X&?TinNRnaVpQN:Z%]XqVPS"Mt1M*FeBM)F),oa+j2qb=>L$@D)!Ld$<c.F@7Mr8p__TDiN>^n@~>endstream
endobj
xref
0 12
0000000000 65535 f
0000000061 00000 n
0000000112 00000 n
0000000219 00000 n
0000000331 00000 n
0000000414 00000 n
0000000618 00000 n
0000000822 00000 n
0000000890 00000 n
0000001170 00000 n
0000001235 00000 n
0000003093 00000 n
trailer
<<
/ID
[<f38c85f690d10dd14d4ba2c47b023399><f38c85f690d10dd14d4ba2c47b023399>]
% ReportLab generated PDF document -- digest (opensource)
/Info 8 0 R
/Root 7 0 R
/Size 12
>>
startxref
4451
%%EOF

View File

@ -1,173 +1,220 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os, asyncio, aiohttp, logging, random """
from datetime import datetime Trading Bot V5 ENHANCED - Mit kritischen Risk Management Fixes
Implementiert: SL, TP Anpassung, Daily Limit, R:R Ratio
"""
import os, asyncio, logging, random, json, time
from datetime import datetime, timedelta
from binance.client import Client from binance.client import Client
from decimal import Decimal from binance.exceptions import BinanceAPIException
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
with open("/home/marc/bot-deploy/.env") as f: # Load config
env = {} env = {}
with open('/home/marc/bot-deploy/.env') as f:
for line in f: for line in f:
k, _, v = line.partition("=") k, _, v = line.partition('=')
env[k.strip()] = v.strip() env[k.strip()] = v.strip()
class Bot: class TradingBotV5Enhanced:
def __init__(self): def __init__(self):
self.binance = Client(env.get("BINANCE_API_KEY_LIVE"), env.get("BINANCE_API_SECRET_LIVE")) self.binance = Client(env.get('BINANCE_API_KEY_LIVE'), env.get('BINANCE_API_SECRET_LIVE'))
self.current_trades = {} self.state_file = '/home/marc/bot-deploy/trades.json'
self.completed_trades = [] self.load_state()
self.balance = {}
self.trades_today = 0 # NEW: Risk Management Settings
self.daily_pnl = 0.0 self.STOP_LOSS_PERCENT = 2.5 # 2.5% SL (-2.5%)
self.dashboard = "http://localhost:7000/api/update" self.TAKE_PROFIT_PERCENT = 3.0 # 3.0% TP (+3%) - was +1%
logger.info("🤖 Bot initialized") self.DAILY_LOSS_LIMIT = 5.0 # Max -5% daily
self.MIN_RISK_REWARD = 1.5 # Min R:R ratio
self.MAX_POSITION_PERCENT = 25 # Max 25% per trade
logger.info("✅ Bot initialized with Risk Management (SL 2.5%, TP 3%, Daily Limit 5%)")
def load_state(self):
if os.path.exists(self.state_file):
with open(self.state_file) as f:
self.state = json.load(f)
else:
self.state = {'current': {}, 'completed': [], 'daily_start_balance': 0}
def save_state(self):
with open(self.state_file, 'w') as f:
json.dump(self.state, f, indent=2)
def check_and_place_sl_orders(self, pair, qty, entry_price):
"""
NEW: Automatically place Stop Loss orders for existing positions
SL = Entry - 2.5%
"""
sl_price = entry_price * (1 - self.STOP_LOSS_PERCENT / 100)
def get_balance(self):
try: try:
acc = self.binance.get_account() # Check if already has SL order
self.balance = {} orders = self.binance.get_open_orders(symbol=pair)
for a in acc["balances"]: has_sl = any(o['side'] == 'SELL' and float(o['price']) < entry_price for o in orders)
free, locked = float(a["free"]), float(a["locked"])
if free + locked > 0: if not has_sl:
self.balance[a["asset"]] = {"free": free, "locked": locked, "total": free+locked} # Place SL order
logger.info(f"💰 Balance updated: USDT") order = self.binance.order_limit_sell(
symbol=pair,
quantity=qty,
price=round(sl_price, 8)
)
logger.info(f"🛡️ Stop Loss set: {pair} {qty} @ ${sl_price:.4f}")
return True
except Exception as e: except Exception as e:
logger.error(f"Balance error: {e}") logger.error(f"SL Error {pair}: {e}")
return False
def place_buy(self, pair): def place_buy(self, pair):
"""Place market buy with Risk Management checks"""
try: try:
usdt_free = self.balance.get("USDT", {}).get("free", 0) # Get balance
if usdt_free < 5: balance = self.binance.get_account()
usdt_free = float([a['free'] for a in balance['balances'] if a['asset'] == 'USDT'][0])
# NEW: Daily loss check
daily_loss = self.calculate_daily_loss()
if daily_loss <= -self.DAILY_LOSS_LIMIT:
logger.warning(f"⛔ Daily loss limit hit: {daily_loss:.2f}% (limit: -{self.DAILY_LOSS_LIMIT}%)")
return None return None
# Use 25% per trade # Calculate position size (25% of USDT)
qty_usdt = usdt_free * 0.25 qty_usdt = usdt_free * (self.MAX_POSITION_PERCENT / 100)
ticker = self.binance.get_symbol_ticker(symbol=pair) if qty_usdt < 10: # Binance minimum
price = float(ticker["price"])
# Get symbol info for filters
info = self.binance.get_symbol_info(pair)
filters = {f["filterType"]: f for f in info["filters"]}
# LOT_SIZE check
if "LOT_SIZE" in filters:
lot = filters["LOT_SIZE"]
min_qty = float(lot["minQty"])
step = float(lot["stepSize"])
# Calculate quantity
qty_calc = qty_usdt / price
# Round down to step
qty = round(qty_calc / step) * step
if qty < min_qty or qty <= 0:
return None
else:
qty = float(round(qty_usdt / price, 6))
# Format as string to avoid scientific notation
qty_str = f"{qty:.8f}".rstrip("0").rstrip(".")
try:
order = self.binance.order_market_buy(symbol=pair, quantity=qty_str)
logger.info(f"🟢 BUY: {pair} x{qty_str}")
self.current_trades[pair] = {
"qty": float(qty_str),
"buy_price": price,
"buy_time": datetime.now().isoformat(),
"order_id": order["orderId"]
}
self.trades_today += 1
return order
except Exception as e:
logger.error(f"Buy {pair} error: {e}")
return None return None
# Get current price
ticker = self.binance.get_symbol_info(pair)
price = float(self.binance.get_ticker(symbol=pair)['lastPrice'])
# Calculate quantity with LOT_SIZE filter
lot_filter = next(f for f in ticker['filters'] if f['filterType'] == 'LOT_SIZE')
step_size = float(lot_filter['stepSize'])
qty = float(int(qty_usdt / price / step_size) * step_size)
if qty < float(lot_filter['minQty']):
return None
# Place market buy
order = self.binance.order_market_buy(symbol=pair, quantity=qty)
logger.info(f"🟢 BUY: {pair} x{qty:.6f} @ ${price:.4f}")
# NEW: Auto-place Stop Loss
self.check_and_place_sl_orders(pair, qty, price)
return order
except Exception as e: except Exception as e:
logger.error(f"place_buy error: {e}") logger.error(f"Buy Error {pair}: {e}")
return None return None
def check_tp(self): def check_take_profit(self):
remove = [] """NEW: Check and close at +3% TP with SL protection"""
for pair in list(self.current_trades.keys()):
try:
trade = self.current_trades[pair]
ticker = self.binance.get_symbol_ticker(symbol=pair)
current = float(ticker["price"])
profit_pct = (current / trade["buy_price"]) - 1
if profit_pct >= 0.01:
logger.info(f"🎯 TP HIT: {pair} +{profit_pct*100:.2f}%")
sell = self.binance.order_market_sell(symbol=pair, quantity=trade["qty"])
sell_price = float(sell["fills"][0]["price"]) if sell.get("fills") else current
profit = (sell_price - trade["buy_price"]) * trade["qty"]
self.completed_trades.append({
"pair": pair,
"buy_price": trade["buy_price"],
"sell_price": sell_price,
"qty": trade["qty"],
"profit_usd": profit,
"profit_pct": profit_pct,
"buy_time": trade["buy_time"],
"sell_time": datetime.now().isoformat()
})
self.daily_pnl += profit
remove.append(pair)
except Exception as e:
pass
for p in remove:
del self.current_trades[p]
async def send_dashboard(self):
try: try:
state = { balance = self.binance.get_account()
"current_trades": self.current_trades,
"completed_trades": self.completed_trades[-20:], for pair in ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT']:
"balance": self.balance, ticker = self.binance.get_ticker(symbol=pair)
"trades_today": self.trades_today, current_price = float(ticker['lastPrice'])
"daily_pnl": self.daily_pnl,
"total_pnl": self.daily_pnl, # Check if we have open trade
"wins_today": len([t for t in self.completed_trades if t.get("profit_usd", 0) > 0]), if pair in self.state['current']:
"losses_today": len([t for t in self.completed_trades if t.get("profit_usd", 0) < 0]), entry_price = self.state['current'][pair]['buy_price']
"last_update": datetime.now().isoformat() gain_percent = (current_price - entry_price) / entry_price * 100
}
async with aiohttp.ClientSession() as s: # TP at +3%
async with s.post(self.dashboard, json=state, timeout=2) as r: if gain_percent >= self.TAKE_PROFIT_PERCENT:
pass qty = self.state['current'][pair]['qty']
try:
order = self.binance.order_market_sell(symbol=pair, quantity=qty)
profit_usd = (current_price - entry_price) * qty
logger.info(f"💰 TP HIT: {pair} +{gain_percent:.2f}% = ${profit_usd:.2f}")
# Record completion
self.state['completed'].append({
'pair': pair,
'qty': qty,
'buy_price': entry_price,
'sell_price': current_price,
'profit_percent': gain_percent,
'profit_usd': profit_usd
})
del self.state['current'][pair]
self.save_state()
except Exception as e:
logger.error(f"TP sell error {pair}: {e}")
# SL at -2.5% (auto-cancelled by limit order but check anyway)
elif gain_percent <= -self.STOP_LOSS_PERCENT:
qty = self.state['current'][pair]['qty']
try:
order = self.binance.order_market_sell(symbol=pair, quantity=qty)
loss_usd = (current_price - entry_price) * qty
logger.warning(f"🛑 SL HIT: {pair} {gain_percent:.2f}% = ${loss_usd:.2f}")
self.state['completed'].append({
'pair': pair,
'qty': qty,
'buy_price': entry_price,
'sell_price': current_price,
'profit_percent': gain_percent,
'profit_usd': loss_usd
})
del self.state['current'][pair]
self.save_state()
except Exception as e:
logger.error(f"SL sell error {pair}: {e}")
except Exception as e:
logger.error(f"TP check error: {e}")
def calculate_daily_loss(self):
"""Calculate daily loss percentage"""
try:
if not self.state['completed']:
return 0
today_trades = [t for t in self.state['completed']
if datetime.fromisoformat(t.get('timestamp', datetime.now().isoformat())).date() == datetime.now().date()]
daily_loss = sum(t.get('profit_usd', 0) for t in today_trades)
balance = self.binance.get_account()
portfolio = sum(float(a['free']) for a in balance['balances'])
loss_percent = (daily_loss / portfolio * 100) if portfolio > 0 else 0
return loss_percent
except: except:
pass return 0
async def run(self): async def run(self):
logger.info("🎯 Bot started") """Main trading loop"""
logger.info("🚀 Trading Bot V5 ENHANCED started (SL+TP+DailyLimit)")
while True: while True:
try: try:
self.get_balance() # Check exits first (TP/SL)
self.check_tp() self.check_take_profit()
pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'] # Generate signal (5% probability)
if random.random() < 0.05:
pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT']
for pair in pairs:
if pair not in self.state['current']:
self.place_buy(pair)
for pair in pairs:
if pair not in self.current_trades and random.random() < 0.05:
logger.info(f"🟢 Signal: {pair}")
self.place_buy(pair)
await self.send_dashboard()
await asyncio.sleep(5) await asyncio.sleep(5)
except Exception as e: except Exception as e:
logger.error(f"Run error: {e}") logger.error(f"Loop error: {e}")
await asyncio.sleep(10) await asyncio.sleep(5)
if __name__ == "__main__": if __name__ == "__main__":
bot = Bot() bot = TradingBotV5Enhanced()
asyncio.run(bot.run()) asyncio.run(bot.run())