mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 00:05:15 +00:00
refine setup steps
This commit is contained in:
parent
b33f08e9a0
commit
17d5e301dc
|
@ -2,12 +2,26 @@ import axios from "axios";
|
|||
|
||||
const baseURL = process.env.NODE_ENV === "development" ? "http://localhost:8080" : ""
|
||||
|
||||
export function testSessionConnection(data, cb) {
|
||||
return axios.post(baseURL + '/api/sessions/test-connection', data, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
}).then(response => {
|
||||
export function testDatabaseConnection(dsn, cb) {
|
||||
return axios.post(baseURL + '/api/setup/test-db', {dsn: dsn}).then(response => {
|
||||
cb(response.data)
|
||||
});
|
||||
}
|
||||
|
||||
export function configureDatabase(dsn, cb) {
|
||||
return axios.post(baseURL + '/api/setup/configure-db', {dsn: dsn}).then(response => {
|
||||
cb(response.data)
|
||||
});
|
||||
}
|
||||
|
||||
export function addSession(session, cb) {
|
||||
return axios.post(baseURL + '/api/sessions', session).then(response => {
|
||||
cb(response.data)
|
||||
});
|
||||
}
|
||||
|
||||
export function testSessionConnection(session, cb) {
|
||||
return axios.post(baseURL + '/api/sessions/test', session).then(response => {
|
||||
cb(response.data)
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import MenuItem from '@material-ui/core/MenuItem';
|
|||
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
|
||||
import {testSessionConnection} from '../api/bbgo';
|
||||
import {addSession, testSessionConnection} from '../api/bbgo';
|
||||
|
||||
import {makeStyles} from '@material-ui/core/styles';
|
||||
|
||||
|
@ -37,7 +37,7 @@ const useStyles = makeStyles((theme) => ({
|
|||
},
|
||||
}));
|
||||
|
||||
export default function ExchangeSessionForm() {
|
||||
export default function AddExchangeSessionForm({onBack, onAdded}) {
|
||||
const classes = useStyles();
|
||||
const [exchangeType, setExchangeType] = React.useState('max');
|
||||
const [customSessionName, setCustomSessionName] = React.useState(false);
|
||||
|
@ -45,6 +45,7 @@ export default function ExchangeSessionForm() {
|
|||
|
||||
const [testing, setTesting] = React.useState(false);
|
||||
const [testResponse, setTestResponse] = React.useState(null);
|
||||
const [response, setResponse] = React.useState(null);
|
||||
|
||||
const [apiKey, setApiKey] = React.useState('');
|
||||
const [apiSecret, setApiSecret] = React.useState('');
|
||||
|
@ -76,6 +77,19 @@ export default function ExchangeSessionForm() {
|
|||
}
|
||||
}
|
||||
|
||||
const handleAdd = (event) => {
|
||||
const payload = createSessionConfig()
|
||||
addSession(payload, (response) => {
|
||||
setResponse(response)
|
||||
if (onAdded) {
|
||||
setTimeout(onAdded, 3000)
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
setResponse(error.response)
|
||||
})
|
||||
};
|
||||
|
||||
const handleTestConnection = (event) => {
|
||||
const payload = createSessionConfig()
|
||||
setTesting(true)
|
||||
|
@ -83,10 +97,10 @@ export default function ExchangeSessionForm() {
|
|||
console.log(response)
|
||||
setTesting(false)
|
||||
setTestResponse(response)
|
||||
}).catch((reason) => {
|
||||
console.error(reason)
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
setTesting(false)
|
||||
setTestResponse(reason)
|
||||
setTestResponse(error.response)
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -174,7 +188,8 @@ export default function ExchangeSessionForm() {
|
|||
}} value="1"/>}
|
||||
label="Use margin trading."
|
||||
/>
|
||||
<FormHelperText id="isMargin-helper-text">This is only available for Binance. Please use the leverage at your own risk.</FormHelperText>
|
||||
<FormHelperText id="isMargin-helper-text">This is only available for Binance. Please use the
|
||||
leverage at your own risk.</FormHelperText>
|
||||
|
||||
<FormControlLabel
|
||||
control={<Checkbox color="secondary" name="isIsolatedMargin"
|
||||
|
@ -184,7 +199,8 @@ export default function ExchangeSessionForm() {
|
|||
}} value="1"/>}
|
||||
label="Use isolated margin trading."
|
||||
/>
|
||||
<FormHelperText id="isIsolatedMargin-helper-text">This is only available for Binance. If this is set, you can only trade one symbol with one session.</FormHelperText>
|
||||
<FormHelperText id="isIsolatedMargin-helper-text">This is only available for Binance. If this is
|
||||
set, you can only trade one symbol with one session.</FormHelperText>
|
||||
|
||||
{isIsolatedMargin ?
|
||||
<TextField
|
||||
|
@ -204,17 +220,28 @@ export default function ExchangeSessionForm() {
|
|||
</Grid>
|
||||
|
||||
<div className={classes.buttons}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (onBack) {
|
||||
onBack();
|
||||
}
|
||||
}}>
|
||||
Back
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
color="primary"
|
||||
onClick={handleTestConnection}
|
||||
disabled={testing}>
|
||||
{ testing ? "Testing" : "Test Connection"}
|
||||
{testing ? "Testing" : "Test Connection"}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary">
|
||||
Create
|
||||
color="primary"
|
||||
onClick={handleAdd}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
@ -230,6 +257,18 @@ export default function ExchangeSessionForm() {
|
|||
) : null : null
|
||||
}
|
||||
|
||||
{
|
||||
response ? response.error ? (
|
||||
<Box m={2}>
|
||||
<Alert severity="error">{response.error}</Alert>
|
||||
</Box>
|
||||
) : response.success ? (
|
||||
<Box m={2}>
|
||||
<Alert severity="success">Exchange Session Added</Alert>
|
||||
</Box>
|
||||
) : null : null
|
||||
}
|
||||
|
||||
|
||||
</React.Fragment>
|
||||
);
|
154
frontend/components/ConfigureDatabaseForm.js
Normal file
154
frontend/components/ConfigureDatabaseForm.js
Normal file
|
@ -0,0 +1,154 @@
|
|||
import React from 'react';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import FormHelperText from '@material-ui/core/FormHelperText';
|
||||
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
|
||||
import {testDatabaseConnection, configureDatabase} from '../api/bbgo';
|
||||
|
||||
import {makeStyles} from '@material-ui/core/styles';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
formControl: {
|
||||
marginTop: theme.spacing(1),
|
||||
marginBottom: theme.spacing(1),
|
||||
minWidth: 120,
|
||||
},
|
||||
buttons: {
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
marginTop: theme.spacing(2),
|
||||
paddingTop: theme.spacing(2),
|
||||
paddingBottom: theme.spacing(2),
|
||||
'& > *': {
|
||||
marginLeft: theme.spacing(1),
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
export default function ConfigureDatabaseForm({ onConfigured }) {
|
||||
const classes = useStyles();
|
||||
|
||||
const [mysqlURL, setMysqlURL] = React.useState("")
|
||||
const [testing, setTesting] = React.useState(false);
|
||||
const [testResponse, setTestResponse] = React.useState(null);
|
||||
const [configured, setConfigured] = React.useState(false);
|
||||
|
||||
const resetTestResponse = () => {
|
||||
setTestResponse(null)
|
||||
}
|
||||
|
||||
const handleConfigureDatabase = (event) => {
|
||||
configureDatabase(mysqlURL, (response) => {
|
||||
console.log(response);
|
||||
setTesting(false);
|
||||
setTestResponse(response);
|
||||
if (onConfigured) {
|
||||
setConfigured(true);
|
||||
setTimeout(onConfigured, 3000);
|
||||
}
|
||||
|
||||
}).catch((reason) => {
|
||||
console.error(reason);
|
||||
setTesting(false);
|
||||
setTestResponse(reason);
|
||||
})
|
||||
}
|
||||
|
||||
const handleTestConnection = (event) => {
|
||||
setTesting(true);
|
||||
testDatabaseConnection(mysqlURL, (response) => {
|
||||
console.log(response)
|
||||
setTesting(false)
|
||||
setTestResponse(response)
|
||||
}).catch((reason) => {
|
||||
console.error(reason)
|
||||
setTesting(false)
|
||||
setTestResponse(reason)
|
||||
})
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Configure Database
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body1" gutterBottom>
|
||||
If you have database installed on your machine, you can enter the DSN string in the following field.
|
||||
Please note this is optional, you CAN SKIP this step.
|
||||
</Typography>
|
||||
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<TextField id="mysql_url" name="mysql_url" label="MySQL Data Source Name"
|
||||
fullWidth
|
||||
required
|
||||
onChange={(event) => {
|
||||
setMysqlURL(event.target.value)
|
||||
resetTestResponse()
|
||||
}}
|
||||
/>
|
||||
|
||||
<FormHelperText id="session-name-helper-text">
|
||||
If you have database installed on your machine, you can enter the DSN string like the
|
||||
following
|
||||
format:
|
||||
<br/>
|
||||
<code>
|
||||
root:password@tcp(127.0.0.1:3306)/bbgo
|
||||
</code>
|
||||
|
||||
<br/>
|
||||
Be sure to create your database before using it. You need to execute the following statement
|
||||
to
|
||||
create a database:
|
||||
<br/>
|
||||
<code>
|
||||
CREATE DATABASE bbgo CHARSET utf8;
|
||||
</code>
|
||||
|
||||
</FormHelperText>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<div className={classes.buttons}>
|
||||
<Button
|
||||
color="primary"
|
||||
onClick={handleTestConnection}
|
||||
disabled={testing || configured}
|
||||
>
|
||||
{testing ? "Testing" : "Test Connection"}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={testing || configured}
|
||||
onClick={handleConfigureDatabase}
|
||||
>
|
||||
Configure
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{
|
||||
testResponse ? testResponse.error ? (
|
||||
<Box m={2}>
|
||||
<Alert severity="error">{testResponse.error}</Alert>
|
||||
</Box>
|
||||
) : testResponse.success ? (
|
||||
<Box m={2}>
|
||||
<Alert severity="success">Connection Test Succeeded</Alert>
|
||||
</Box>
|
||||
) : null : null
|
||||
}
|
||||
|
||||
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
}
|
89
frontend/components/ReviewSessions.js
Normal file
89
frontend/components/ReviewSessions.js
Normal file
|
@ -0,0 +1,89 @@
|
|||
import React from 'react';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import List from '@material-ui/core/List';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import PowerIcon from '@material-ui/icons/Power';
|
||||
|
||||
import {makeStyles} from '@material-ui/core/styles';
|
||||
import {querySessions} from "../api/bbgo";
|
||||
import {Power} from "@material-ui/icons";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
formControl: {
|
||||
marginTop: theme.spacing(1),
|
||||
marginBottom: theme.spacing(1),
|
||||
minWidth: 120,
|
||||
},
|
||||
buttons: {
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
marginTop: theme.spacing(2),
|
||||
paddingTop: theme.spacing(2),
|
||||
paddingBottom: theme.spacing(2),
|
||||
'& > *': {
|
||||
marginLeft: theme.spacing(1),
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
export default function ReviewSessions({onBack, onNext}) {
|
||||
const classes = useStyles();
|
||||
|
||||
const [sessions, setSessions] = React.useState([]);
|
||||
|
||||
React.useEffect(() => {
|
||||
querySessions((sessions) => {
|
||||
setSessions(sessions)
|
||||
});
|
||||
}, [])
|
||||
|
||||
const items = sessions.map((session, i) => {
|
||||
console.log(session)
|
||||
return (
|
||||
<ListItem key={session.name}>
|
||||
<ListItemIcon>
|
||||
<PowerIcon/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={session.name} secondary={session.exchange}/>
|
||||
</ListItem>
|
||||
);
|
||||
})
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Review Sessions
|
||||
</Typography>
|
||||
|
||||
<List component="nav">
|
||||
{items}
|
||||
</List>
|
||||
|
||||
<div className={classes.buttons}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (onBack) {
|
||||
onBack();
|
||||
}
|
||||
}}>
|
||||
Back
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
if (onNext) {
|
||||
onNext();
|
||||
}
|
||||
}}>
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
|
@ -8,7 +8,9 @@ import Stepper from '@material-ui/core/Stepper';
|
|||
import Step from '@material-ui/core/Step';
|
||||
import StepLabel from '@material-ui/core/StepLabel';
|
||||
|
||||
import ExchangeSessionForm from "../../components/ExchangeSessionForm";
|
||||
import ConfigureDatabaseForm from "../../components/ConfigureDatabaseForm";
|
||||
import AddExchangeSessionForm from "../../components/AddExchangeSessionForm";
|
||||
import ReviewSessions from "../../components/ReviewSessions";
|
||||
|
||||
import PlainLayout from '../../layouts/PlainLayout';
|
||||
|
||||
|
@ -20,14 +22,24 @@ const useStyles = makeStyles((theme) => ({
|
|||
|
||||
const steps = ['Configure Database', 'Add Exchange Session', 'Configure Strategy', 'Restart BBGO'];
|
||||
|
||||
function getStepContent(step) {
|
||||
function getStepContent(step, setActiveStep) {
|
||||
switch (step) {
|
||||
case 0:
|
||||
return;
|
||||
return <ConfigureDatabaseForm onConfigured={() => {
|
||||
setActiveStep(1)
|
||||
}}/>;
|
||||
case 1:
|
||||
return <ExchangeSessionForm/>;
|
||||
return <AddExchangeSessionForm onAdded={() => {
|
||||
setActiveStep(2)
|
||||
}} onBack={() => {
|
||||
setActiveStep(0)
|
||||
}}/>;
|
||||
case 2:
|
||||
return;
|
||||
return <ReviewSessions onBack={() => {
|
||||
setActiveStep(1)
|
||||
}} onNext={() => {
|
||||
setActiveStep(3)
|
||||
}}/>
|
||||
case 3:
|
||||
return;
|
||||
default:
|
||||
|
@ -56,7 +68,7 @@ export default function Setup() {
|
|||
</Stepper>
|
||||
|
||||
<React.Fragment>
|
||||
{getStepContent(activeStep)}
|
||||
{getStepContent(activeStep, setActiveStep)}
|
||||
</React.Fragment>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
|
|
@ -164,7 +164,7 @@ type Config struct {
|
|||
|
||||
Persistence *PersistenceConfig `json:"persistence,omitempty" yaml:"persistence,omitempty"`
|
||||
|
||||
Sessions map[string]Session `json:"sessions,omitempty" yaml:"sessions,omitempty"`
|
||||
Sessions map[string]*ExchangeSession `json:"sessions,omitempty" yaml:"sessions,omitempty"`
|
||||
|
||||
RiskControls *RiskControls `json:"riskControls,omitempty" yaml:"riskControls,omitempty"`
|
||||
|
||||
|
|
|
@ -75,21 +75,17 @@ func (environ *Environment) Sessions() map[string]*ExchangeSession {
|
|||
return environ.sessions
|
||||
}
|
||||
|
||||
func (environ *Environment) ConfigureDatabase(ctx context.Context) error {
|
||||
if viper.IsSet("mysql-url") {
|
||||
dsn := viper.GetString("mysql-url")
|
||||
db, err := ConnectMySQL(dsn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := upgradeDB(ctx, "mysql", db.DB); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
environ.SetDB(db)
|
||||
func (environ *Environment) ConfigureDatabase(ctx context.Context, dsn string) error {
|
||||
db, err := ConnectMySQL(dsn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := upgradeDB(ctx, "mysql", db.DB); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
environ.SetDB(db)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -142,7 +138,7 @@ func (environ *Environment) AddExchangesByViperKeys() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func NewExchangeSessionFromConfig(name string, sessionConfig Session) (*ExchangeSession, error) {
|
||||
func NewExchangeSessionFromConfig(name string, sessionConfig *ExchangeSession) (*ExchangeSession, error) {
|
||||
exchangeName, err := types.ValidExchangeName(sessionConfig.ExchangeName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -175,13 +171,13 @@ func NewExchangeSessionFromConfig(name string, sessionConfig Session) (*Exchange
|
|||
}
|
||||
|
||||
session := NewExchangeSession(name, exchange)
|
||||
session.IsMargin = sessionConfig.Margin
|
||||
session.IsIsolatedMargin = sessionConfig.IsolatedMargin
|
||||
session.Margin = sessionConfig.Margin
|
||||
session.IsolatedMargin = sessionConfig.IsolatedMargin
|
||||
session.IsolatedMarginSymbol = sessionConfig.IsolatedMarginSymbol
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (environ *Environment) AddExchangesFromSessionConfig(sessions map[string]Session) error {
|
||||
func (environ *Environment) AddExchangesFromSessionConfig(sessions map[string]*ExchangeSession) error {
|
||||
for sessionName, sessionConfig := range sessions {
|
||||
session, err := NewExchangeSessionFromConfig(sessionName, sessionConfig)
|
||||
if err != nil {
|
||||
|
|
|
@ -136,8 +136,59 @@ func RunServer(ctx context.Context, userConfig *Config, environ *Environment, tr
|
|||
return
|
||||
})
|
||||
|
||||
r.POST("/api/sessions/test-connection", func(c *gin.Context) {
|
||||
var sessionConfig Session
|
||||
r.POST("/api/setup/test-db", func(c *gin.Context) {
|
||||
payload := struct {
|
||||
DSN string `json:"dsn"`
|
||||
}{}
|
||||
|
||||
if err := c.BindJSON(&payload); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "missing arguments"})
|
||||
return
|
||||
}
|
||||
|
||||
dsn := payload.DSN
|
||||
if len(dsn) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "missing dsn argument"})
|
||||
return
|
||||
}
|
||||
|
||||
db, err := ConnectMySQL(dsn)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
_ = db.Close()
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"success": true})
|
||||
})
|
||||
|
||||
r.POST("/api/setup/configure-db", func(c *gin.Context) {
|
||||
payload := struct {
|
||||
DSN string `json:"dsn"`
|
||||
}{}
|
||||
|
||||
if err := c.BindJSON(&payload); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "missing arguments"})
|
||||
return
|
||||
}
|
||||
|
||||
dsn := payload.DSN
|
||||
if len(dsn) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "missing dsn argument"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := environ.ConfigureDatabase(ctx, dsn); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"success": true})
|
||||
})
|
||||
|
||||
r.POST("/api/sessions", func(c *gin.Context) {
|
||||
var sessionConfig ExchangeSession
|
||||
if err := c.BindJSON(&sessionConfig); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
|
@ -145,7 +196,31 @@ func RunServer(ctx context.Context, userConfig *Config, environ *Environment, tr
|
|||
return
|
||||
}
|
||||
|
||||
session, err := NewExchangeSessionFromConfig(sessionConfig.ExchangeName, sessionConfig)
|
||||
session, err := NewExchangeSessionFromConfig(sessionConfig.ExchangeName, &sessionConfig)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
environ.AddExchangeSession(sessionConfig.Name, session)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
})
|
||||
})
|
||||
|
||||
r.POST("/api/sessions/test", func(c *gin.Context) {
|
||||
var sessionConfig ExchangeSession
|
||||
if err := c.BindJSON(&sessionConfig); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
session, err := NewExchangeSessionFromConfig(sessionConfig.ExchangeName, &sessionConfig)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
|
@ -173,7 +248,7 @@ func RunServer(ctx context.Context, userConfig *Config, environ *Environment, tr
|
|||
})
|
||||
|
||||
r.GET("/api/sessions", func(c *gin.Context) {
|
||||
var sessions []*ExchangeSession
|
||||
var sessions = []*ExchangeSession{}
|
||||
for _, session := range environ.Sessions() {
|
||||
sessions = append(sessions, session)
|
||||
}
|
||||
|
|
|
@ -100,18 +100,29 @@ type ExchangeSession struct {
|
|||
// we make it as a value field so that we can configure it separately
|
||||
Notifiability `json:"-"`
|
||||
|
||||
// ---------------------------
|
||||
// Session config fields
|
||||
// ---------------------------
|
||||
|
||||
// Exchange Session name
|
||||
Name string `json:"name"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
ExchangeName string `json:"exchange" yaml:"exchange"`
|
||||
EnvVarPrefix string `json:"envVarPrefix" yaml:"envVarPrefix"`
|
||||
Key string `json:"key,omitempty" yaml:"key,omitempty"`
|
||||
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
|
||||
|
||||
PublicOnly bool `json:"publicOnly,omitempty" yaml:"publicOnly"`
|
||||
Margin bool `json:"margin,omitempty" yaml:"margin"`
|
||||
IsolatedMargin bool `json:"isolatedMargin,omitempty" yaml:"isolatedMargin,omitempty"`
|
||||
IsolatedMarginSymbol string `json:"isolatedMarginSymbol,omitempty" yaml:"isolatedMarginSymbol,omitempty"`
|
||||
|
||||
// ---------------------------
|
||||
// Runtime fields
|
||||
// ---------------------------
|
||||
|
||||
// The exchange account states
|
||||
Account *types.Account `json:"account"`
|
||||
|
||||
IsMargin bool `json:"isMargin"`
|
||||
|
||||
IsIsolatedMargin bool `json:"isIsolatedMargin,omitempty"`
|
||||
|
||||
IsolatedMarginSymbol string `json:"isolatedMarginSymbol,omitempty"`
|
||||
|
||||
IsInitialized bool `json:"isInitialized"`
|
||||
|
||||
// Stream is the connection stream of the exchange
|
||||
|
|
|
@ -116,8 +116,11 @@ var BacktestCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
environ := bbgo.NewEnvironment()
|
||||
if err := environ.ConfigureDatabase(ctx); err != nil {
|
||||
return err
|
||||
if viper.IsSet("mysql-url") {
|
||||
dsn := viper.GetString("mysql-url")
|
||||
if err := environ.ConfigureDatabase(ctx, dsn); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
backtestService := &service.BacktestService{DB: db}
|
||||
|
|
|
@ -88,8 +88,11 @@ func runConfig(basectx context.Context, userConfig *bbgo.Config, enableApiServer
|
|||
|
||||
environ := bbgo.NewEnvironment()
|
||||
|
||||
if err := environ.ConfigureDatabase(ctx); err != nil {
|
||||
return err
|
||||
if viper.IsSet("mysql-url") {
|
||||
dsn := viper.GetString("mysql-url")
|
||||
if err := environ.ConfigureDatabase(ctx, dsn); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := environ.AddExchangesFromConfig(userConfig); err != nil {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
)
|
||||
|
@ -51,8 +52,12 @@ var SyncCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
environ := bbgo.NewEnvironment()
|
||||
if err := environ.ConfigureDatabase(ctx); err != nil {
|
||||
return err
|
||||
|
||||
if viper.IsSet("mysql-url") {
|
||||
dsn := viper.GetString("mysql-url")
|
||||
if err := environ.ConfigureDatabase(ctx, dsn); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := environ.AddExchangesFromConfig(userConfig); err != nil {
|
||||
|
@ -108,7 +113,7 @@ var SyncCmd = &cobra.Command{
|
|||
func syncSession(ctx context.Context, environ *bbgo.Environment, session *bbgo.ExchangeSession, symbol string, startTime time.Time) error {
|
||||
log.Infof("starting syncing exchange session %s", session.Name)
|
||||
|
||||
if session.IsIsolatedMargin {
|
||||
if session.IsolatedMargin {
|
||||
log.Infof("session is configured as isolated margin session, using isolated margin symbol %s instead of %s", session.IsolatedMarginSymbol, symbol)
|
||||
symbol = session.IsolatedMarginSymbol
|
||||
}
|
||||
|
|
|
@ -78,8 +78,9 @@ case "$command" in
|
|||
if [[ -n $currency ]] ; then
|
||||
rewards_params[currency]=$currency
|
||||
fi
|
||||
|
||||
# rewards rewards_params | jq -r '.[] | "\(.type)\t\((.amount | tonumber) * 1000 | floor / 1000)\t\(.currency) \(.state) \(.created_at | strflocaltime("%Y-%m-%dT%H:%M:%S %Z"))"'
|
||||
rewards rewards_params | jq -r '.[] | [ .type, ((.amount | tonumber) * 10000 | floor / 10000), .currency, .state, (.created_at | strflocaltime("%Y-%m-%dT%H:%M:%S %Z")) ] | @tsv' \
|
||||
rewards rewards_params | jq -r '.[] | [ .uuid, .type, ((.amount | tonumber) * 10000 | floor / 10000), .currency, .state, (.created_at | strflocaltime("%Y-%m-%dT%H:%M:%S %Z")), .note ] | @tsv' \
|
||||
| column -ts $'\t'
|
||||
;;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user