package common import ( "fmt" "regexp" "strings" gctorder "github.com/thrasher-corp/gocryptotrader/exchanges/order" "github.com/thrasher-corp/gocryptotrader/log" ) // CanTransact checks whether an order side is valid // to the backtester's standards func CanTransact(side gctorder.Side) bool { return side.IsLong() || side.IsShort() || side == gctorder.ClosePosition } // DataTypeToInt converts the config string value into an int func DataTypeToInt(dataType string) (int64, error) { switch dataType { case CandleStr: return DataCandle, nil case TradeStr: return DataTrade, nil default: return 0, fmt.Errorf("unrecognised dataType '%v'", dataType) } } // GenerateFileName will convert a proposed filename into something that is more // OS friendly func GenerateFileName(fileName, extension string) (string, error) { if fileName == "" { return "", fmt.Errorf("%w missing filename", errCannotGenerateFileName) } if extension == "" { return "", fmt.Errorf("%w missing filename extension", errCannotGenerateFileName) } reg := regexp.MustCompile(`[\w-]`) parsedFileName := reg.FindAllString(fileName, -1) parsedExtension := reg.FindAllString(extension, -1) fileName = strings.Join(parsedFileName, "") + "." + strings.Join(parsedExtension, "") return strings.ToLower(fileName), nil } // FitStringToLimit ensures a string is of the length of the limit // either by truncating the string with ellipses or padding with the spacer func FitStringToLimit(str, spacer string, limit int, upper bool) string { if limit < 0 { return str } if limit == 0 { return "" } limResp := limit - len(str) if upper { str = strings.ToUpper(str) } if limResp < 0 { if limit-3 > 0 { return str[0:limit-3] + "..." } return str[0:limit] } spacerLen := len(spacer) for i := 0; i < limResp; i++ { str += spacer for j := 0; j < spacerLen; j++ { if j > 0 { // prevent clever people from going beyond // the limit by having a spacer longer than 1 i++ } } } return str[0:limit] } // RegisterBacktesterSubLoggers sets up all custom Backtester sub-loggers func RegisterBacktesterSubLoggers() error { var err error Backtester, err = log.NewSubLogger("Backtester") if err != nil { return err } LiveStrategy, err = log.NewSubLogger("LiveStrategy") if err != nil { return err } Setup, err = log.NewSubLogger("Setup") if err != nil { return err } Strategy, err = log.NewSubLogger("Strategy") if err != nil { return err } Report, err = log.NewSubLogger("Report") if err != nil { return err } Statistics, err = log.NewSubLogger("Statistics") if err != nil { return err } CurrencyStatistics, err = log.NewSubLogger("CurrencyStatistics") if err != nil { return err } FundingStatistics, err = log.NewSubLogger("FundingStatistics") if err != nil { return err } Holdings, err = log.NewSubLogger("Holdings") if err != nil { return err } Data, err = log.NewSubLogger("Data") if err != nil { return err } FundManager, err = log.NewSubLogger("FundManager") if err != nil { return err } // Set to existing registered sub-loggers Config = log.ConfigMgr Portfolio = log.PortfolioMgr Exchange = log.ExchangeSys Fill = log.Fill return nil } // PurgeColours removes colour information func PurgeColours() { CMDColours.Green = "" CMDColours.White = "" CMDColours.Grey = "" CMDColours.Default = "" CMDColours.H1 = "" CMDColours.H2 = "" CMDColours.H3 = "" CMDColours.H4 = "" CMDColours.Success = "" CMDColours.Info = "" CMDColours.Debug = "" CMDColours.Warn = "" CMDColours.DarkGrey = "" CMDColours.Error = "" } // SetColours sets cmd output colours at startup. Doing it at any other point // risks races and this really isn't worth adding a mutex for func SetColours(colours *Colours) { if colours.Default != "" && colours.Default != CMDColours.Default { CMDColours.Default = colours.Default } if colours.Green != "" && colours.Green != CMDColours.Green { CMDColours.Green = colours.Green } if colours.Error != "" && colours.Error != CMDColours.Error { CMDColours.Error = colours.Error } if colours.White != "" && colours.White != CMDColours.White { CMDColours.White = colours.White } if colours.Grey != "" && colours.Grey != CMDColours.Grey { CMDColours.Grey = colours.Grey } if colours.H1 != "" && colours.H1 != CMDColours.H1 { CMDColours.H1 = colours.H1 } if colours.H2 != "" && colours.H2 != CMDColours.H2 { CMDColours.H2 = colours.H2 } if colours.H3 != "" && colours.H3 != CMDColours.H3 { CMDColours.H3 = colours.H3 } if colours.H4 != "" && colours.H4 != CMDColours.H4 { CMDColours.H4 = colours.H4 } if colours.Success != "" && colours.Error != CMDColours.Success { CMDColours.Success = colours.Success } if colours.Info != "" && colours.Info != CMDColours.Info { CMDColours.Info = colours.Info } if colours.Debug != "" && colours.Debug != CMDColours.Debug { CMDColours.Debug = colours.Debug } if colours.Warn != "" && colours.Warn != CMDColours.Warn { CMDColours.Warn = colours.Warn } if colours.DarkGrey != "" && colours.DarkGrey != CMDColours.DarkGrey { CMDColours.DarkGrey = colours.DarkGrey } } // Logo returns the logo func Logo() string { sb := strings.Builder{} sb.WriteString(" \n") sb.WriteString(" " + CMDColours.White + "@@@@@@@@@@@@@@@@@ \n") sb.WriteString(" " + CMDColours.White + "@@@@@@@@@@@@@@@@@@@@@@@ " + CMDColours.Grey + ",,,,,," + CMDColours.White + " \n") sb.WriteString(" " + CMDColours.White + "@@@@@@@@" + CMDColours.Grey + ",,,,, " + CMDColours.White + "@@@@@@@@@" + CMDColours.Grey + ",,,,,,,," + CMDColours.White + " \n") sb.WriteString(" " + CMDColours.White + "@@@@@@@@" + CMDColours.Grey + ",,,,,,, " + CMDColours.White + "@@@@@@@" + CMDColours.Grey + ",,,,,,," + CMDColours.White + " \n") sb.WriteString(" " + CMDColours.White + "@@@@@@" + CMDColours.Grey + "(,,,,,,,, " + CMDColours.Grey + ",," + CMDColours.White + "@@@@@@@" + CMDColours.Grey + ",,,,,," + CMDColours.White + " \n") sb.WriteString(" " + CMDColours.Grey + ",," + CMDColours.White + "@@@@@@" + CMDColours.Grey + ",,,,,,,,, #,,,,,,,,,,,,,,,,,," + CMDColours.White + " \n") sb.WriteString(" " + CMDColours.Grey + ",,,,*" + CMDColours.White + "@@@@@@" + CMDColours.Grey + ",,,,,,,,,,,,,,,,,,,,,,,,,," + CMDColours.Green + "%%%%%%%" + CMDColours.White + " \n") sb.WriteString(" " + CMDColours.Grey + ",,,,,,,*" + CMDColours.White + "@@@@@@" + CMDColours.Grey + ",,,,,,,,,,,,,," + CMDColours.Green + "%%%%%" + CMDColours.Grey + " ,,,,,," + CMDColours.Grey + "%" + CMDColours.Green + "%%%%%%" + CMDColours.White + " \n") sb.WriteString(" " + CMDColours.Grey + ",,,,,,,,*" + CMDColours.White + "@@@@@@" + CMDColours.Grey + ",,,,,,,,,,," + CMDColours.Green + "%%%%%%%%%%%%%%%%%%" + CMDColours.Grey + "#" + CMDColours.Green + "%%" + CMDColours.Grey + " \n") sb.WriteString(" " + CMDColours.Grey + ",,,,,,*" + CMDColours.White + "@@@@@@" + CMDColours.Grey + ",,,,,,,,," + CMDColours.Green + "%%%" + CMDColours.Grey + " ,,,,," + CMDColours.Green + "%%%%%%%%" + CMDColours.Grey + ",,,,, \n") sb.WriteString(" " + CMDColours.Grey + ",,,*" + CMDColours.White + "@@@@@@" + CMDColours.Grey + ",,,,,," + CMDColours.Green + "%%" + CMDColours.Grey + ",, ,,,,,,," + CMDColours.White + "@" + CMDColours.Green + "*%%," + CMDColours.White + "@" + CMDColours.Grey + ",,,,,, \n") sb.WriteString(" " + CMDColours.Grey + "*" + CMDColours.White + "@@@@@@" + CMDColours.Grey + ",,,,,,,,, " + CMDColours.Grey + ",,,,," + CMDColours.White + "@@@@@@" + CMDColours.Grey + ",,,,,," + CMDColours.White + " \n") sb.WriteString(" " + CMDColours.White + "@@@@@@" + CMDColours.Grey + ",,,,,,,,, " + CMDColours.White + "@@@@@@@" + CMDColours.Grey + ",,,,,," + CMDColours.White + " \n") sb.WriteString(" " + CMDColours.White + "@@@@@@@@" + CMDColours.Grey + ",,,,,,, " + CMDColours.White + "@@@@@@@" + CMDColours.Grey + ",,,,,,," + CMDColours.White + " \n") sb.WriteString(" " + CMDColours.White + "@@@@@@@@@" + CMDColours.Grey + ",,,, " + CMDColours.White + "@@@@@@@@@" + CMDColours.Grey + "#,,,,,,," + CMDColours.White + " \n") sb.WriteString(" " + CMDColours.White + "@@@@@@@@@@@@@@@@@@@@@@@ " + CMDColours.Grey + "*,,,," + CMDColours.White + " \n") sb.WriteString(" " + CMDColours.White + "@@@@@@@@@@@@@@@@" + CMDColours.Default + " \n") sb.WriteString(ASCIILogo) return sb.String() }