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
def get_balance(self): self.MAX_POSITION_PERCENT = 25 # Max 25% per trade
try:
acc = self.binance.get_account() logger.info("✅ Bot initialized with Risk Management (SL 2.5%, TP 3%, Daily Limit 5%)")
self.balance = {}
for a in acc["balances"]: def load_state(self):
free, locked = float(a["free"]), float(a["locked"]) if os.path.exists(self.state_file):
if free + locked > 0: with open(self.state_file) as f:
self.balance[a["asset"]] = {"free": free, "locked": locked, "total": free+locked} self.state = json.load(f)
logger.info(f"💰 Balance updated: USDT") else:
except Exception as e: self.state = {'current': {}, 'completed': [], 'daily_start_balance': 0}
logger.error(f"Balance error: {e}")
def save_state(self):
def place_buy(self, pair): with open(self.state_file, 'w') as f:
try: json.dump(self.state, f, indent=2)
usdt_free = self.balance.get("USDT", {}).get("free", 0)
if usdt_free < 5: def check_and_place_sl_orders(self, pair, qty, entry_price):
return None """
NEW: Automatically place Stop Loss orders for existing positions
# Use 25% per trade SL = Entry - 2.5%
qty_usdt = usdt_free * 0.25 """
sl_price = entry_price * (1 - self.STOP_LOSS_PERCENT / 100)
ticker = self.binance.get_symbol_ticker(symbol=pair)
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
except Exception as e:
logger.error(f"place_buy error: {e}")
return None
def check_tp(self):
remove = []
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 = { # Check if already has SL order
"current_trades": self.current_trades, orders = self.binance.get_open_orders(symbol=pair)
"completed_trades": self.completed_trades[-20:], has_sl = any(o['side'] == 'SELL' and float(o['price']) < entry_price for o in orders)
"balance": self.balance,
"trades_today": self.trades_today, if not has_sl:
"daily_pnl": self.daily_pnl, # Place SL order
"total_pnl": self.daily_pnl, order = self.binance.order_limit_sell(
"wins_today": len([t for t in self.completed_trades if t.get("profit_usd", 0) > 0]), symbol=pair,
"losses_today": len([t for t in self.completed_trades if t.get("profit_usd", 0) < 0]), quantity=qty,
"last_update": datetime.now().isoformat() price=round(sl_price, 8)
} )
async with aiohttp.ClientSession() as s: logger.info(f"🛡️ Stop Loss set: {pair} {qty} @ ${sl_price:.4f}")
async with s.post(self.dashboard, json=state, timeout=2) as r: return True
pass except Exception as e:
logger.error(f"SL Error {pair}: {e}")
return False
def place_buy(self, pair):
"""Place market buy with Risk Management checks"""
try:
# Get balance
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
# Calculate position size (25% of USDT)
qty_usdt = usdt_free * (self.MAX_POSITION_PERCENT / 100)
if qty_usdt < 10: # Binance minimum
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:
logger.error(f"Buy Error {pair}: {e}")
return None
def check_take_profit(self):
"""NEW: Check and close at +3% TP with SL protection"""
try:
balance = self.binance.get_account()
for pair in ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT']:
ticker = self.binance.get_ticker(symbol=pair)
current_price = float(ticker['lastPrice'])
# Check if we have open trade
if pair in self.state['current']:
entry_price = self.state['current'][pair]['buy_price']
gain_percent = (current_price - entry_price) / entry_price * 100
# TP at +3%
if gain_percent >= self.TAKE_PROFIT_PERCENT:
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())