Skip to content

Commit

Permalink
upd
Browse files Browse the repository at this point in the history
  • Loading branch information
m5l14i11 committed Sep 6, 2024
1 parent 72279fb commit 907b7f0
Show file tree
Hide file tree
Showing 33 changed files with 447 additions and 837 deletions.
18 changes: 9 additions & 9 deletions config.default.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ buf_size = 50
base_dir = tmp

[bus]
piority_groups = 21
piority_groups = 8
num_workers = 5

[backtest]
batch_size = 455
batch_size = 350
buff_size = 8
window_size = 2
window_size = 1

[position]
trade_duration = 16800
trade_duration = 26800
twap_duration = 80
max_order_slice = 8
order_expiration_time = 8
Expand All @@ -22,7 +22,7 @@ dom = 15
max_scale_in = 0

[portfolio]
risk_per_trade = 0.001
risk_per_trade = 0.0004
account_size = 1000
cagr_threshold = 0.01
sharpe_ratio_threshold = 0.23
Expand All @@ -36,12 +36,12 @@ leverage = 75
reevaluate_timeout = 3600

[generator]
n_samples = 13
n_samples = 8
blacklist = [USDCUSDT]
timeframes = [5m]

[optimization]
max_generations = 5
max_generations = 3
elite_count = 3
mutation_rate = 0.0236
crossover_rate = 0.8
Expand All @@ -55,5 +55,5 @@ n_ctx = 4096
n_threads = 7
n_gpu_layers = 2
n_batch = 256
max_tokens = 86
temperature = 0.6
max_tokens = 66
temperature = 0.52
60 changes: 33 additions & 27 deletions copilot/_actor.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import asyncio
import logging
import re
from typing import Union

import numpy as np
from core.models.strategy_type import StrategyType
from scipy.spatial.distance import cdist
from sklearn.cluster import KMeans
from sklearn.metrics import calinski_harabasz_score, silhouette_score, davies_bouldin_score
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.utils import check_random_state
from sklearn.decomposition import KernelPCA, PCA
from sklearn.svm import OneClassSVM
from sklearn.decomposition import PCA, KernelPCA
from sklearn.ensemble import IsolationForest
from sklearn.metrics import (
calinski_harabasz_score,
davies_bouldin_score,
silhouette_score,
)
from sklearn.mixture import BayesianGaussianMixture
from sklearn.neighbors import LocalOutlierFactor
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from sklearn.svm import OneClassSVM
from sklearn.utils import check_random_state

from core.actors import BaseActor
from core.interfaces.abstract_llm_service import AbstractLLMService
Expand All @@ -25,9 +29,7 @@

from ._prompt import (
signal_contrarian_risk_prompt,
signal_risk_pattern,
signal_trend_risk_prompt,
system_prompt,
)

CopilotEvent = Union[EvaluateSignal, EvaluateSession]
Expand Down Expand Up @@ -169,11 +171,11 @@ async def _evaluate_signal(self, msg: EvaluateSignal) -> SignalRisk:
)

bar = sorted(prev_bar + [curr_bar], key=lambda x: x.timestamp)
strategy_type = "Contrarian" if "SUP" not in str(signal.strategy) else "Trend"
strategy_type = StrategyType.CONTRARIAN if "SUP" not in str(signal.strategy) else StrategyType.TREND_FOLLOW

template = (
signal_contrarian_risk_prompt
if strategy_type == "Contrarian"
if strategy_type == StrategyType.CONTRARIAN
else signal_trend_risk_prompt
)

Expand Down Expand Up @@ -219,10 +221,12 @@ async def _evaluate_signal(self, msg: EvaluateSignal) -> SignalRisk:

tp, sl = float(f"{_tp[0]}.{_tp[1]}"), float(f"{_sl[0]}.{_sl[1]}")

unknow_risk = (tp > curr_bar.close and side == PositionSide.SHORT) or (tp < curr_bar.close and side == PositionSide.LONG)
unknow_risk = (tp > curr_bar.close and side == PositionSide.SHORT) or (
tp < curr_bar.close and side == PositionSide.LONG
)

if unknow_risk:
logger.warn(f"Risk with unknown position management")
logger.warn("Risk with unknown position management")

risk = SignalRisk(type=risk_type, tp=tp, sl=sl)

Expand Down Expand Up @@ -278,7 +282,7 @@ async def _evaluate_session(self, msg: EvaluateSession) -> SessionRiskType:
features = MinMaxScaler(feature_range=(-1, 1)).fit_transform(features)

features = PCA(n_components=5).fit_transform(features)
features = KernelPCA(n_components=2, kernel='rbf').fit_transform(features)
features = KernelPCA(n_components=2, kernel="rbf").fit_transform(features)

n_neighbors = len(features) - 1
max_clusters = min(n_neighbors, 10)
Expand All @@ -297,31 +301,35 @@ async def _evaluate_session(self, msg: EvaluateSession) -> SessionRiskType:
db_score = davies_bouldin_score(features, kmeans.labels_)

combined_score = (score + sil_score - db_score) / 3

if combined_score > k_best_score:
k_best_score = combined_score
k_best_labels = kmeans.labels_

k_cluster_labels = k_best_labels.reshape(-1, 1)

features_with_clusters = np.hstack((features, k_cluster_labels))

iso_forest = IsolationForest(contamination=0.01, random_state=1337).fit(features_with_clusters)
iso_forest = IsolationForest(contamination=0.01, random_state=1337).fit(
features_with_clusters
)
iso_anomaly = iso_forest.predict(features_with_clusters) == -1

lof = LocalOutlierFactor(n_neighbors=n_neighbors, contamination=0.01)
lof_anomaly = lof.fit_predict(features_with_clusters) == -1

one_class_svm = OneClassSVM(kernel='rbf', gamma='scale', nu=0.01)
one_class_svm = OneClassSVM(kernel="rbf", gamma="scale", nu=0.01)
svm_anomaly = one_class_svm.fit_predict(features_with_clusters) == -1

iso_scores = iso_forest.decision_function(features_with_clusters)
lof_scores = -lof.negative_outlier_factor_
svm_score = one_class_svm.decision_function(features_with_clusters)

anomaly_scores = 0.3 * iso_scores + 0.2 * lof_scores + 0.5 * svm_score

bgmm = BayesianGaussianMixture(n_components=2, covariance_type='full', random_state=1337)
bgmm = BayesianGaussianMixture(
n_components=2, covariance_type="full", random_state=1337
)
bgmm.fit(anomaly_scores.reshape(-1, 1))

dynamic_threshold = np.percentile(bgmm.means_, 5)
Expand All @@ -330,20 +338,18 @@ async def _evaluate_session(self, msg: EvaluateSession) -> SessionRiskType:
should_exit = False

confidence_scores = {
'knn_transaction': 0.4 if knn_transaction in self.anomaly else 0,
'anomaly_score': 0.2 if anomaly_scores[-1] < dynamic_threshold else 0,
'iso_anomaly': 0.3 if iso_anomaly[-1] else 0,
'lof_anomaly': 0.05 if lof_anomaly[-1] else 0,
'svm_anomaly': 0.05 if svm_anomaly[-1] else 0,
"knn_transaction": 0.4 if knn_transaction in self.anomaly else 0,
"anomaly_score": 0.2 if anomaly_scores[-1] < dynamic_threshold else 0,
"iso_anomaly": 0.3 if iso_anomaly[-1] else 0,
"lof_anomaly": 0.05 if lof_anomaly[-1] else 0,
"svm_anomaly": 0.05 if svm_anomaly[-1] else 0,
}

if sum(confidence_scores.values()) > 0.5:
should_exit = True

logger.info(
f"SIDE: {msg.side}, "
f"HLCC4: {hlcc4[-1]}, "
f"Exit: {should_exit}"
f"SIDE: {msg.side}, " f"HLCC4: {hlcc4[-1]}, " f"Exit: {should_exit}"
)

if should_exit:
Expand Down
8 changes: 6 additions & 2 deletions copilot/_prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@
- HIGH: Significant risk factors, high caution or avoidance advised.
- VERY_HIGH: Major risk factors, generally unfavorable.
"""
signal_trend_risk_prompt = f"{risk_intro}{risk_data}{trend_risk_framework}{risk_eval}{risk_outro}"
signal_contrarian_risk_prompt = f"{risk_intro}{risk_data}{contrarian_risk_framework}{risk_eval}{risk_outro}"
signal_trend_risk_prompt = (
f"{risk_intro}{risk_data}{trend_risk_framework}{risk_eval}{risk_outro}"
)
signal_contrarian_risk_prompt = (
f"{risk_intro}{risk_data}{contrarian_risk_framework}{risk_eval}{risk_outro}"
)
signal_risk_pattern = r"RL:\s*(NONE|VERY_LOW|LOW|MODERATE|HIGH|VERY_HIGH)\s*,\s*TP:\s*([\d.]+)\s*,\s*SL:\s*([\d.]+)\s*\.*"
50 changes: 4 additions & 46 deletions core/models/position.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def exit_price(self) -> float:
@property
def curr_price(self) -> float:
last_bar = self.risk_bar

return (2 * last_bar.close + last_bar.high + last_bar.low) / 4.0

@property
Expand Down Expand Up @@ -291,21 +291,11 @@ def next(
targets = next_position.profit_target.targets[1:]
raw_forecast = next_position.position_risk.forecast(steps=3)

print(f"Targets: {targets[:8]}")

rising = False
forecast = None
long = next_position.side == PositionSide.LONG

if raw_forecast:
forecast = raw_forecast[-1]
rising = (
raw_forecast[0] <= raw_forecast[-1]
if long
else raw_forecast[0] > raw_forecast[-1]
)

# print(f"Forecast: {raw_forecast}, rising: {rising}")

stp = (
next_position.signal_risk.tp
Expand All @@ -322,8 +312,6 @@ def next(

ttp = (w_stp * stp + w_ftp * ftp + w_sstp * sstp) / (w_stp + w_sstp + w_ftp)

print(f"Signal TP: {stp}, forecast TP: {ftp}, S/R TP: {sstp}, TTP: {ttp}")

def target_filter(target, tp):
sl = next_position.stop_loss
curr_price = next_position.curr_price
Expand All @@ -346,8 +334,6 @@ def target_filter(target, tp):
idx_rr = i
break

print(f"RR Idx: {idx_rr}, RR: {rr}")

idx_tg = 0
for i, target in enumerate(targets):
if target_filter(target, ttp):
Expand All @@ -369,44 +355,26 @@ def target_filter(target, tp):
exit_ratio = exit_dist / entry_price
dist_ratio = dist / entry_price
is_exit = session_risk == SessionRiskType.EXIT
has_risk = next_position.signal_risk.type in {SignalRiskType.MODERATE, SignalRiskType.HIGH}

# print(f"Targets: {targets}")
print(
f"Trail target: {trail_target}, PRED_TP: {next_tp}, "
f"CURR_DIST: {dist:.6f} ({dist_ratio:.2%}), "
f"TR_DIST: {trl_dist:.6f} ({trl_ratio:.2%}), "
f"EXIT_DIST: {exit_dist:.6f} ({exit_ratio:.2%})"
)

trail_threshold = 0.0008

print(f"____________RATIO: {trl_ratio}___________")

if dist > trl_dist and trl_ratio > trail_threshold:
print("Activating trailing stop mechanism")
logger.info("Activating trailing stop mechanism")
next_position = next_position.trail(ta)

if is_exit:
exit_ratio = exit_dist / entry_price
dist_ratio = dist / entry_price

if exit_ratio > 0.005:
print(
f"TRAIL PREV SL: {next_position.stop_loss:.6f}, "
f"CURR PRICE: {next_position.risk_bar.close:.6f}, "
f"CURR_DIST: {dist:.6f} ({dist_ratio:.2%}), "
f"EXIT_DIST: {exit_dist:.6f} ({exit_ratio:.2%})"
)

next_position = next_position.trail(ta)

print(
logger.info(
f"TRAIL NEXT SL: {next_position.stop_loss:.6f}, "
f"CURR PRICE: {next_position.risk_bar.close:.6f}"
)
else:
print(
logger.info(
f"Exit condition not met: "
f"CURR_DIST: {dist:.6f} ({dist_ratio:.2%}), "
f"EXIT_DIST: {exit_dist:.6f} ({exit_ratio:.2%})"
Expand All @@ -420,9 +388,6 @@ def target_filter(target, tp):
sl = curr_price + half if long else curr_price - half
next_sl = max(sl, next_sl) if long else min(sl, next_sl)

if next_sl != next_position.stop_loss:
print(f"Change Dist SL: {next_sl}")

next_risk = next_risk.assess(
next_position.side,
next_tp,
Expand All @@ -432,7 +397,6 @@ def target_filter(target, tp):
)

if next_risk.type == PositionRiskType.TP:
print("RESET RISK")
next_risk = next_risk.reset()
index = 0

Expand All @@ -444,8 +408,6 @@ def target_filter(target, tp):
idx = min(max(DEFAULT_TARGET_IDX, index + 1), len(targets) - 1)
next_tp = targets[idx]

print(f"Update TP: {next_tp}, SL: {next_sl}")

next_position = replace(
self,
position_risk=next_risk,
Expand All @@ -464,10 +426,6 @@ def trail(self, ta: TechAnalysis) -> "Position":
prev_sl = self.stop_loss
next_sl = self.position_risk.sl_ats(self.side, ta, prev_sl)

logger.info(
f"<---- &&&&&&TRAIL&&&&& -->>> prevSL: {prev_sl}, nextSL: {next_sl}"
)

return replace(self, _sl=next_sl, last_modified=datetime.now().timestamp())

def theo_taker_fee(self, size: float, price: float) -> float:
Expand Down
Loading

0 comments on commit 907b7f0

Please sign in to comment.