feat(strategy): expose configurable nick contract

This commit is contained in:
2026-08-15 23:38:18 +09:00
parent acfaab7fd4
commit e6a90800ec
8 changed files with 189 additions and 60 deletions
+9 -1
View File
@@ -243,7 +243,14 @@ class PortfolioRepository(Protocol):
def get_or_create_strategy_set(self, name: str, config: str) -> StrategySet: ...
def create_strategy_set(self, name: str, config: str, *, status: str = "active") -> StrategySet: ...
def create_strategy_set(
self,
name: str,
config: str,
*,
nick: str | None = None,
status: str = "active",
) -> StrategySet: ...
def get_strategy_set(self, id: str) -> StrategySet | None: ...
@@ -254,6 +261,7 @@ class PortfolioRepository(Protocol):
id: str,
*,
name: str | None = None,
nick: str | None = None,
config: str | None = None,
status: str | None = None,
) -> StrategySet: ...
+36 -24
View File
@@ -1360,28 +1360,38 @@ class PostgresPortfolioRepository:
def get_or_create_strategy_set(self, name: str, config: str) -> StrategySet:
return self.create_strategy_set(name, config)
def create_strategy_set(self, name: str, config: str, *, status: str = "active") -> StrategySet:
def create_strategy_set(
self,
name: str,
config: str,
*,
nick: str | None = None,
status: str = "active",
) -> StrategySet:
self.ensure_schema()
nick = f"{name}:{hashlib.sha1(config.encode('utf-8')).hexdigest()[:12]}"
with self._connect().cursor() as cur:
new_id = str(uuid.uuid4())
cur.execute(
"""
INSERT INTO strategy_sets (id, name, config, nick, status)
VALUES (%s, %s, %s, %s, %s)
ON CONFLICT (name, config) DO NOTHING
""",
(new_id, name, config, nick, status),
)
cur.execute(
"""
SELECT id, name, config, nick, status, revision, created_at, updated_at
FROM strategy_sets
WHERE name = %s AND config = %s
""",
(name, config),
)
row = cur.fetchone()
final_nick = nick or f"{name}:{hashlib.sha1(config.encode('utf-8')).hexdigest()[:12]}"
try:
with self._connect().cursor() as cur:
new_id = str(uuid.uuid4())
cur.execute(
"""
INSERT INTO strategy_sets (id, name, config, nick, status)
VALUES (%s, %s, %s, %s, %s)
ON CONFLICT (name, config) DO NOTHING
""",
(new_id, name, config, final_nick, status),
)
cur.execute(
"""
SELECT id, name, config, nick, status, revision, created_at, updated_at
FROM strategy_sets
WHERE name = %s AND config = %s
""",
(name, config),
)
row = cur.fetchone()
except psycopg.errors.UniqueViolation as exc:
raise ValueError("동일한 nick 전략이 이미 존재합니다") from exc
return self._row_to_strategy_set(row)
def get_strategy_set(self, id: str) -> StrategySet | None:
@@ -1414,6 +1424,7 @@ class PostgresPortfolioRepository:
id: str,
*,
name: str | None = None,
nick: str | None = None,
config: str | None = None,
status: str | None = None,
) -> StrategySet:
@@ -1435,15 +1446,16 @@ class PostgresPortfolioRepository:
raise ValueError("전략을 찾을 수 없습니다")
current = self._row_to_strategy_set(row)
final_name = name if name is not None else current.name
final_nick = nick if nick is not None else current.nick
final_config = config if config is not None else current.config
final_status = status if status is not None else current.status
if (
final_name == current.name
and final_nick == current.nick
and final_config == current.config
and final_status == current.status
):
return current
nick = f"{final_name}:{hashlib.sha1(final_config.encode('utf-8')).hexdigest()[:12]}"
cur.execute(
"""
UPDATE strategy_sets
@@ -1456,11 +1468,11 @@ class PostgresPortfolioRepository:
WHERE id = %s
RETURNING id, name, config, nick, status, revision, created_at, updated_at
""",
(final_name, final_config, nick, final_status, id),
(final_name, final_config, final_nick, final_status, id),
)
updated = cur.fetchone()
except psycopg.errors.UniqueViolation as exc:
raise ValueError("동일한 name/config 전략이 이미 존재합니다") from exc
raise ValueError("동일한 name/config 또는 nick 전략이 이미 존재합니다") from exc
if updated is None:
raise ValueError("전략을 찾을 수 없습니다")
return self._row_to_strategy_set(updated)