๐Ÿ“– star365 Docs
โ† ๋ณด๊ณ ์„œ ๋ชฉ๋ก

multi-tenant hedge mode unify sprint ๋ณด๊ณ ์„œ


0. ๋ฐœ๋‹จ

ok1000 cash_point ๋ถ„์„ โ†’ user 16 ๊ฑฐ๋ž˜ ์ •๋ฐ€ ์ ๊ฒ€(์ „์ž„ sprint) โ†’ admin tenant ๋น„๊ต โ†’ ๊ฐ™์€ ์ฝ”๋“œ์ธ๋ฐ ๊ฒฐ๊ณผ ์ •๋ฐ˜๋Œ€ ๋ฐœ๊ฒฌ:

admin user 16
5/8 +$226.32 (15W/0L) โˆ’$199.72 (0W/1L) โ†’ daily SL pause
5/9 +$105.17 (7W/0L) โˆ’$32.31 (0W/2L)
5์›” ๋ˆ„์  +$617.89 โœ… โˆ’$94.22 โŒ

์ฝ”๋“œ ํŠธ๋ ˆ์ด์Šค ๊ฒฐ๊ณผ multi_tenant_agent.py:111์ด is_hedge_mode=False ๊ฐ•์ œ โ†’ user์˜ Bitget ๊ณ„์ • mode์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ one-way๋กœ ํŠธ๋ ˆ์ด๋”ฉ โ†’ ํŽ˜์–ด ํ—ค์ง€ NPV ๋ˆ„์ˆ˜ ๋ฐœ์ƒ.


1. ๋‹จ๊ณ„์  ์ „ํ™˜ ๊ฒฐ์ •

์‚ฌ์šฉ์ž ๋ช…๋ น: "multi-tenant๋„ hedge mode๋กœ ๋ณ€๊ฒฝ, ๊ด€๋ฆฌ์ž์™€ ๋ชจ๋‘ ๋™์ผํ•ด์•ผ ํ•œ๋‹ค"

์œ„ํ—˜ ๋ถ„์„ ํ›„ 3๋‹จ๊ณ„ ์ œ์•ˆ โ†’ ์‚ฌ์šฉ์ž ๊ฒฐ์ • = Phase A๋งŒ

Phase ๋‚ด์šฉ ๊ฒฐ์ •
A ์ฝ”๋“œ ๊ฐ•์ œ one-way ์ œ๊ฑฐ, admin๊ณผ ๋™์ผํ•œ ์ž๋™ ๊ฐ์ง€ ๋„์ž… โœ… ์ ์šฉ
B user 16 Bitget ๊ณ„์ • hedge mode ์นด๋‚˜๋ฆฌ ์ „ํ™˜ ๋ณด๋ฅ˜ (์šด์˜์ง„)
C ๋‚˜๋จธ์ง€ user ์ˆœ์ฐจ ์ „ํ™˜ ๋ณด๋ฅ˜ (์šด์˜์ง„)

Phase A ๋‹จ๋…์œผ๋กœ๋„ ์˜๋ฏธ ํผ: user๊ฐ€ ๋ณธ์ธ Bitget ์•ฑ์—์„œ hedge๋กœ ๋ณ€๊ฒฝํ•ด๋‘๋ฉด ์‹œ์Šคํ…œ์ด ์ž๋™ ๊ฐ์ง€ โ†’ user ์ž์œจ ๊ฒฐ์ • ๊ตฌ์กฐ.


2. ์ฝ”๋“œ ๋ณ€๊ฒฝ

Before (multi_tenant_agent.py:107-111)

# 1.1 Position Mode: ๊ธฐ๋ณธ์ ์œผ๋กœ One-way mode ์‚ฌ์šฉ
# Multi-Tenant ์œ ์ € ๋Œ€๋ถ€๋ถ„์ด one-way mode๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ์•ˆ์ „ํ•˜๊ฒŒ one-way๋กœ ๊ธฐ๋ณธ ์„ค์ •
# Pair Hedge๋Š” one-way mode์—์„œ๋„ ์ž‘๋™ (ํ•œ๋ฒˆ์— ํ•œ ๋ฐฉํ–ฅ๋งŒ ๊ฐ€๋Šฅ)
self.is_hedge_mode = False
logger.info(f"[{user_id}] Using one-way mode (default for multi-tenant)")

After

# 1.1 Position Mode: admin๊ณผ ๋™์ผํ•œ ์ž๋™ ๊ฐ์ง€ (2026-05-10 unify)
# ๊ธฐ์กด one-way ๊ฐ•์ œ ์ •์ฑ… ์ œ๊ฑฐ โ†’ ๊ฐ user์˜ Bitget ๊ณ„์ • mode๋ฅผ fetch_positions๋กœ ์ถ”๋ก 
# ํ™œ์„ฑ ํฌ์ง€์…˜ ์ค‘ hedged=True๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด hedge mode, ์•„๋‹ˆ๋ฉด one-way
# admin/scripts/run_pair_hedge_trading.py์˜ ํŒจํ„ด(line 128~141)๊ณผ ์ •ํ™•ํžˆ ๋™์ผ
self.is_hedge_mode = False
try:
    positions = self.exchange.fetch_positions()
    for pos in positions:
        if float(pos.get('contracts', 0)) > 0:
            pos_mode = pos.get('hedged', False)
            if pos_mode:
                self.is_hedge_mode = True
                break
except Exception as e:
    logger.warning(f"[{user_id}] Could not detect hedge mode: {e}")
logger.info(f"[{user_id}] Hedge Mode: {self.is_hedge_mode} (auto-detected, unified with admin)")

3. ์žฌ์‹œ์ž‘ ๊ฒ€์ฆ

systemctl restart gunja-multi-tenant
โ†’ Active: active (running) since Sat 2026-05-09 16:48:23 UTC

์ž๋™ ๊ฐ์ง€ ๊ฒฐ๊ณผ (๊ฐ user)

user hedge mode capital ์ƒํƒœ
1 False $0.00 SKIP_LOW_CAPITAL
3 False $0.00 SKIP_LOW_CAPITAL
16 โœ… True $546.40 (free $72.99) ํ™œ์„ฑ, ์ด๋ฏธ Bitget์—์„œ hedge์˜€์Œ
24 โœ… True $760.22 ํ™œ์„ฑ (ํŽ˜์–ด 6๊ฐœ ๋ณด์œ )
26 True $67.24 SKIP_LOW_CAPITAL
27 True โ€“ ํ™œ์„ฑ

๐Ÿšจ ํ•ต์‹ฌ ๋ฐœ๊ฒฌ

user 16์€ ์ด๋ฏธ Bitget ๊ณ„์ •์—์„œ hedge mode์˜€๋‹ค. ์ฝ”๋“œ๋งŒ one-way๋กœ ๊ฐ•์ œํ•˜๊ณ  ์žˆ์—ˆ์„ ๋ฟ.
โ†’ 5/8 โˆ’$199, 5/9 โˆ’$32 ์†์‹ค์˜ root cause = ๊ฑฐ๋ž˜์†Œ๋Š” hedge์ธ๋ฐ ์‹œ์Šคํ…œ์€ one-way๋กœ ์šด์šฉ = ํŽ˜์–ด ํ—ค์ง€ ๋น„ํšจ์œจ ๊ทธ ์ž์ฒด.

์ด์ „ ๋ณด๊ณ ์„œ(stage8-ewallet-filter ๋‹ค์Œ sprint)์˜ "ํŽ˜์–ด NPV ๋ˆ„์ˆ˜ ๊ฐ€์„ค" ์ •ํ™•ํžˆ ์ž…์ฆ.


4. ๋ผ์ด๋ธŒ ์ ๊ฒ€


5. ๋‹ค์Œ ๋ชจ๋‹ˆํ„ฐ๋ง ํฌ์ธํŠธ

์‹œ์  ์ ๊ฒ€
+24h (5/10 17:00 UTC) user 16 ์ƒˆ ์ง„์ž… ์‹œ hedge ๋™์ž‘ ํ™•์ธ. 5/8-9 ๊ฐ™์€ ์†์‹ค ํŒจํ„ด ์žฌ๋ฐœ ์—ฌ๋ถ€
+72h user 16 5์›” ๋ˆ„์  net์ด โˆ’$94.22์—์„œ ํšŒ๋ณตํ•˜๋Š” ์ถ”์„ธ ํ™•์ธ
+1์ฃผ์ผ user 24/27 hedge ๋ชจ๋“œ์—์„œ admin ์ˆ˜์ค€ win rate(86%+) ๊ทผ์ ‘ ์—ฌ๋ถ€

ํšŒ๊ท€ ๋ฐœ์ƒ ์‹œ ๋กค๋ฐฑ:

cp /opt/gunja/src/multi_user/multi_tenant_agent.py.bak-20260510-hedge-unify \
   /opt/gunja/src/multi_user/multi_tenant_agent.py
systemctl restart gunja-multi-tenant

6. ๋ฏธ์ ์šฉ (๋ณ„๋„ sprint)


7. ๊ฒฐ๋ก 

Phase A ๋‹จ๋… ์ ์šฉ๋งŒ์œผ๋กœ 6 user ์ „์›์ด ๋ณธ์ธ Bitget mode๋ฅผ ์ž์œจ์ ์œผ๋กœ ๋”ฐ๋ผ๊ฐ€๋Š” ๊ตฌ์กฐ ์™„์„ฑ. ์ถ”๊ฐ€ ๊ฑฐ๋ž˜์†Œ mode ์ „ํ™˜ ์ž‘์—…์ด ์‚ฌ์‹ค์ƒ 0๊ฐœ๋กœ ์ค„์—ˆ๋‹ค(์ด๋ฏธ ๋ชจ๋‘ hedge ์‚ฌ์šฉ ์ค‘).

"๊ด€๋ฆฌ์ž์™€ ๋ชจ๋‘ ๋™์ผ" โ€” ์ฝ”๋“œ 100% ๋™์ผ, mode 6/6 ์ผ์น˜, ์ „๋žตยทconfigยทexecutor ๊ณต์œ .