From a07d255d77ad81bbf7d06121f7994d8277c9b530 Mon Sep 17 00:00:00 2001 From: lychiyu Date: Sun, 4 Aug 2024 23:49:16 +0800 Subject: [PATCH] add pause trade --- config/ccinr.yaml | 56 +++++++++++++++++------- otp.png | Bin 3113 -> 2941 bytes pkg/notifier/larknotifier/lark.go | 3 +- pkg/strategy/ccinr/strategy.go | 69 ++++++++++++++++++++++++++++-- 4 files changed, 107 insertions(+), 21 deletions(-) diff --git a/config/ccinr.yaml b/config/ccinr.yaml index cc3183e..4897f4b 100644 --- a/config/ccinr.yaml +++ b/config/ccinr.yaml @@ -7,13 +7,13 @@ # db: 0 sessions: - binance_futures: + binance: exchange: binance envVarPrefix: BINANCE futures: true exchangeStrategies: - - on: binance_futures + - on: binance ccinr: symbols: - ARUSDT @@ -24,17 +24,17 @@ exchangeStrategies: - DYDXUSDT - XRPUSDT - PEOPLEUSDT -# - STXUSDT -# - WLDUSDT -# - FILUSDT -# - DOGEUSDT -# - MKRUSDT -# - NOTUSDT -# - ENSUSDT -# - BNBUSDT -# - BTCUSDT -# - ETHUSDT -# - SOLUSDT + # - STXUSDT + # - WLDUSDT + # - FILUSDT + # - DOGEUSDT + # - MKRUSDT + # - NOTUSDT + # - ENSUSDT + # - BNBUSDT + # - BTCUSDT + # - ETHUSDT + # - SOLUSDT interval: 1m nrInterval: 1m @@ -55,9 +55,33 @@ exchangeStrategies: placePriceType: 2 lossType: 1 profitOrderType: 0 - atrProfitRange: 0.8 - atrLossRange: 1.0 + atrProfitRange: 1.0 + atrLossRange: 2.0 + tradeStartHour: 0 + tradeEndHour: 8 + pauseTradeLoss: -10.0 # recalculate: false # dry_run: false # # quantity: 3 -# strict_mode: true \ No newline at end of file +# strict_mode: true + +backtest: + startTime: "2023-10-15" + endTime: "2024-08-02" + symbols: + - ARUSDT + - ORDIUSDT + - OPUSDT + - OMUSDT + - WIFUSDT + - DYDXUSDT + - XRPUSDT + - PEOPLEUSDT + sessions: [ binance ] + syncSecKLines: true + accounts: + binance: + takerFeeRate: 0.0002 + makerFeeRate: 0.0005 + balances: + USDT: 200 \ No newline at end of file diff --git a/otp.png b/otp.png index 54c6e89e3eda6830fb7e7b9ccc2779fc8745bc99..95829548e2d637dc48dd2f3c732d9a0a2a7e352f 100644 GIT binary patch literal 2941 zcmai0e^8V68Gi-6mIy^J&1T^!-QfT)R}ZU*G=XSwP&-SsDP)t0MAp)yj-Qej2}w)^ zGB>2IZq=KR-0IC-yh&nH0{9Z%07F`wL}oey$@@kaKPpMyHxR>%zJ%;$f6d+H&E4nT zd;fXf_xV1bAJ6yVvHZLkMjQhGfS4oi9{vCTBB<90U>o%W6c>aa0l?P7M-CtQu)f{x z7^sNP{L#VjC37%%Kg*u`Vb=Dck8dYU+Mph+|l zz)ueXu2Ic_^vyERTR-o-9Hustv35pYe-^vx47kRSDrm;q5omoABKx0Lej5c0ZVnA& zu3}-znF+o1RWJOAfMOslcAvca(34)!I6_}3`ythf3_MWpK}omuio?lRyP|%cl@Dx7 z4h>^EgA1lCj&^j!y^bUnAi-BPxnlg4WmM`pc}f~fU%WD(>b2Oq-Uc5&#Q;|m8Td{o z-R}!`z~Wp5-0<@!aOp?x<+5l;=K+5L?!=p_Ck0OX(J((;a@l6qZ(0Q_8G2P5E;R=K zk<9f=!Hfl2_o?stO=Mlf`Ls%#2N-W1?v zW@t!W+tSbZS3~*c6>OWQY0tQzbkZWc1`*=9%%eL_IAP2HIv>yzlr2kmjhoJWTXe8~ zFl}DDXIu&rPf+ASBiILG*`E|C6!7-Y4cOzhWT)?6b6b1dO^BX(uU*}7*AOMSnG#)s z+a+IwncOoM&yk>zib28R@6>l#s~Cm^K#u?SC(d=Vm_|N)pT2d}!RR|Z_{s#nzltMr zE$`CEVoBUs(+pvkk~o|G-+uq=M%(>VFR#yiJ!Sz-_(WCJ-0K`3&Ei5Flr!CJ2v*=V z^pt&Cq!2og=>~$So@$|NRN_XY4?%+AtgCd`>3hxw*L~XUHt5DJQYT$OT5hF8@8a1L zTeJK-@nYidSqJF*&X{6wMX7bzZhKj6UI~HN+o6W$GR-{+(fN2YAc_c$%8D&$Vu6XX zFB3fPpLAG^!3XNQg9gC_0uO3`QbqC1+Zo!DD_^r#ZSgTSlstodJkguXRjT`>4b8_( z9>>z9)tN0SeXV%d7od#Mp*Im22V?{qM&VR=5ieCx-XRx#tW1fLHx zx3&mf^f`1RE~)Y+(F|k(hqWG)hSK``JEo1S9jiGsV^0jO|1hf^c+ea97c#lkoo{O) z-B{scfpd60tG(y5Fp1q7p`L1&P*G-0oijw`d;`MWy@Y-SHG39WE0c`qwJ%>>F)wI* zVWL0K&^Oy;O87cR3Sza(`?;_|Pm z!8{DC1$!FjuB-LGB>zO;`N?=H7j{GNuDVWUQHk&rR8wZ@w}aK-hz~Ih>e_)fj)sQ& z-=;%@kff3yQ;KfHLwVW?23D63c@Rmxm@s(kWI-5vD{h-X;!$T0G~}PuR?iBG#Qd0h z`8GCpdJHR`_IHKJrLS4_gR-fp92J@DHg!PkRqO6~sOT%07dDO8l~+$DjCG`qWr~hI z#m;*jOQ;kad6W`8#4}JziKp2E7NS@Tej}di(&QFU%GxFqm&Yz^+3j(8#l6ZhHf&(+ z1>?h<`}z$tQ{0npd!w;D3Gat;M!}a#ahVU4yDXTeUQBPc&rc~M`Ik;+L!1+m@^5|C zcb_Ze?@QXU~ApAQs);ggrjMk|?FOWMMgM(GmP-77wugC z*%hT3uehk9I1Hm$(|>PACDqt(mmCT^3slw$G11&J6j|bm_N}2GpQh)YT7)W>_40y4 zdY4SnTMAoh2@uERmFx+VB$kZ@o`;dVvMqwg>DsemJ@3^b5L@_*4Zl(Dwd8xAX5G0m zMZZ<3h~r-}W6mM%?JkYOqzwGwpMnb`8Y7{KySTm%C(!pUseN@7EBu}X5>NAcl!BsG zB4a$8<3B4~etk9|(Nns8lSa3nM@imS=%z!ZXmBe41cQHkh%)yQ@4UBhuRij#{KK8^ HlzjFd+`oH$ literal 3113 zcmai1eM}R18Xlm@S~ucHms|pf-s#cY^-Oh@<4a@}jmH6l5hJeUL+UBp6lhWU#S}zc z@3y+sbsOYETCzE%YmN`S!j>`}idYnIg$Q1O(xGex71~bukPcAVUj2VNn>?A!KW~2T zJiq6C-e)8yz~h@XhHeA^U{mtnj-CX7K;LU1u*LTTu3pc)005uPCm%h0N?3104;P)+ zgnaQT=DnMv+248sK>s0YbHqNqcAx%m`c|S)xNddmyg^6ZxHAmEwgMX{e&AxS59Q`6 z&3*aszpC;RCnUe0Ma@g^6K=OWUhKG2#s0QQj3+KEDfW5_Fkok@AK0Gmp6av8ieY8T z=^Ty|HYP0anTt04eRP1A-vBRmgmB#3H9-}71AZNkIH`fs`kK284JO$xqGeo6Eaptw ztj%L?xk5-+w>)-=(10&$fM3U$W%ra7OFQ!tnUo|5RQ&XvEw;ai-ACV3Aon2m6Cf|p z4|HE`<6cmreUfZ0JzHSF62#O-Pmw)G+z{`FE+37IdXkv+_c_C)8kIpXH8j1xM|%mS zn9WTT<)+&vSNtV{6U{XwaakrhKtcy1G^o-u7`GtGY=NxByVO43GRS*2o1%ts#kQ6TU&%) z$J6b=*JMA~qX^c19`ch*LyhddXnujQG-&)fn5sp(S~+S)#uc_#N2m+1`v~o+EsfcEN(u`cEnO{hBxAzHv zEs=iUtdv)b&_(Aqo5@u0-wBVe7xhZYg!HmcVC5M>`iebqcAVgw-Jiw>Wac=UWf|U8 zUV5swc`Tte)@5RhG^iUtfZFPIa}|L;Tzknv<{E2e`C@A^^GM;$^f&`rx+srf;mfn# z)rTAd4$->DM4)EfBg(wq(|(8H5cNt}ZIle@F1p+!wvsHbqWIp13G#;ZB!7zjogh%E zfFY(;UB3n~7Yk+(Q{8>>>}69a7D~id-ZriQlc>>*D^w>*F@`$VlHpxcFsX|-_W@(u zJlQWV6R0|ONhP2*P8HeTLS?OHjI65$lN3BlbejulI*9-Ljz>^?D?UKLh&?96dB=<7 zLKymU@w7fzhmI7|)2>V!$uXaMvxpk^UGxOK?3`f2#^cy8-$S15QAfT3vv5Oy564YN zb2LA&tEAM{{3q2NipvWA%x)1&Lty0$nDs`F4N!D60q~t)edST726EbsAYA2`GF;B| zk(^b`d^cGHE17l@$+MF{mnzUEj91YMF%3+`2U9EDOYHT#Ll9H_OA|DrA{vM=S%n(> z(JlFCJ20r7#AG))@;Wi|$R&fM|9KQqsn4G!NV#e>ArF6-U3&szaVBs2CJ>WVWNHue z#=Q*&dPsiI^=yBVns1hKnLTrQ9AEQ3#~yYv;BZda5S$(sp;HjgLX7zR+gT+A!pbf8 z(dG>H@tnl$RYP!p2$jFJjzo&w;Kz8%&Tr$cdGt^vx2b9rj+zlN=@x9HE{$7m zA!yhW>Rpl`9966O5_)G;>EXjs%h9e5R96{7mw%;Q>=6A1Q+>?|g|IS+V=oHJ7R(^p zw#}UB<+5+7{4m8Mr(l}k=&pU_7&iW}T{T)GZ)4Qf8 zpdbnn*L3+=*Kn|I{GHSkcWmWBGK`KQQJZ4_>+%Zl4@!AO_YQy6hf)KYEX+J(Hvazf*KLMI9xJEW;cuy z7-m@wDXaGTxCIksL_lp>SUY7&Q97jB1N(&RKa^Aw>4O_LFQJ^vw;$s143d#TPMXnu z*Da-s+^TV(%^mg|H^A;MeG7@Nt43SZ(8+}d@*6Pqbx~TTVnugwfpM=4J4j?2zUiI+ zp_;En%8l0MeieiA%`UqAyKqg^A3GOK`*jdO?N1#P?uCuBdU87rOpV1n;q)}jtskjM zU;pQ1+{_peNn^gfaFgxqR6DJern-X=tF!=bGc{++qWFP`9Ii(cF5WiUL>WbR zCv7RzfT7UrH-_YH8s$1YO(r$fX?^a>^0yCmLiId?ijz&6h7 zOQs|aQQ^r~L>m_i zDW@A(a}sZeZj4;LO7_R?$1KNMW8wM= s.TradeStartHour && hour < s.TradeEndHour +} + +func (s *Strategy) isPauseTrade(ctx context.Context) bool { + // 被暂停次数不为0,且最近一次的暂停时间和今天一致,则表示暂停 + if s.PauseTradeCount != fixedpoint.Zero && s.PauseTradeTime.Day() == time.Now().Day() { + return true + } + // 总收益大于(暂停次数+1)*暂停亏损,则表示暂停 + if s.TotalProfit < s.PauseTradeLoss.Mul(s.PauseTradeCount.Add(fixedpoint.One)) { + s.PauseTradeCount.Add(fixedpoint.One) + s.PauseTradeTime = time.Now() + return true + } + + return false +} + func (s *Strategy) Run(ctx context.Context, orderExecutor qbtrade.OrderExecutor, session *qbtrade.ExchangeSession) error { s.ExchangeSession = session @@ -427,6 +477,8 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor qbtrade.OrderExecutor, s.TotalOrderCount = 0 s.TotalProfitCount = 0 s.TotalLossCount = 0 + s.PauseTradeCount = fixedpoint.Zero + s.PauseTradeTime = time.Now().Add(-24 * time.Hour) for _, symbol := range s.Symbols { s.Positions[symbol] = types.NewPositionFromMarket(s.markets[symbol]) @@ -481,6 +533,15 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor qbtrade.OrderExecutor, if s.Traded[sym] { return } + + if !s.isTradeTime(ctx) || s.isPauseTrade(ctx) { + pauseMsg := fmt.Sprintf("暂停交易:总收益:%v, 暂停次数:%v, 暂停时间:%v; 暂停时间段:[%v, %v)", + s.TotalProfit.Float64(), s.PauseTradeCount.Float64(), s.PauseTradeTime, s.TradeStartHour, + s.TradeEndHour) + qbtrade.Notify(pauseMsg) + return + } + cciV := s.cci[sym].Last(0) if cciV <= s.LongCCI.Float64() { s.TradeType[sym] = "long"