Merge pull request #10 from Superalgos/develop
Merge develop to master for production
This commit is contained in:
9 files changed
+598
-142
No files matched your search
+294
-119
@@ -1,99 +1,24 @@
|
||||
import mongoose, { Schema } from 'mongoose';
|
||||
|
||||
const strategySchema = new Schema({
|
||||
fbId: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
dropDups: true,
|
||||
},
|
||||
subStrategies: [{
|
||||
name: {
|
||||
const strategySchema = new Schema(
|
||||
{
|
||||
fbSlug: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true,
|
||||
unique: true,
|
||||
dropDups: true,
|
||||
},
|
||||
entryPoint: {
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
},
|
||||
exitPoint: {
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
},
|
||||
sellPoint: {
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
},
|
||||
buyPoint: {
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
},
|
||||
stopLoss: {
|
||||
phases: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
subStrategies: [{
|
||||
active: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: true,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
entryPoint: {
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
@@ -110,18 +35,8 @@ const strategySchema = new Schema({
|
||||
},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
buyOrder: {
|
||||
phases: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
},
|
||||
exitPoint: {
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
@@ -138,18 +53,8 @@ const strategySchema = new Schema({
|
||||
},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
sellOrder: {
|
||||
phases: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
},
|
||||
sellPoint: {
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
@@ -166,10 +71,280 @@ const strategySchema = new Schema({
|
||||
},
|
||||
}],
|
||||
}],
|
||||
},
|
||||
buyPoint: {
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
},
|
||||
stopLoss: {
|
||||
phases: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
buyOrder: {
|
||||
phases: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
sellOrder: {
|
||||
phases: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
}],
|
||||
history: [{
|
||||
updatedAt: Date,
|
||||
subStrategies: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
entryPoint: {
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
},
|
||||
exitPoint: {
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
},
|
||||
sellPoint: {
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
},
|
||||
buyPoint: {
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
},
|
||||
stopLoss: {
|
||||
phases: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
buyOrder: {
|
||||
phases: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
sellOrder: {
|
||||
phases: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
situations: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conditions: [{
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
default: 'false',
|
||||
},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
}],
|
||||
},
|
||||
}],
|
||||
});
|
||||
}],
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
},
|
||||
);
|
||||
|
||||
const Strategy = mongoose.model('Strategy', strategySchema);
|
||||
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
import {
|
||||
GraphQLNonNull,
|
||||
GraphQLString,
|
||||
} from 'graphql';
|
||||
import { StrategyType } from '../types';
|
||||
import { Strategy } from '../../models';
|
||||
import { StrategyInputType } from '../types/input';
|
||||
import defaultStrategy from '../../templates/strategyTemplate';
|
||||
|
||||
export const args = {
|
||||
fbSlug: { type: new GraphQLNonNull(GraphQLString) },
|
||||
strategy: { type: StrategyInputType },
|
||||
};
|
||||
|
||||
const resolve = (parent, { strategy }) => {
|
||||
const resolve = (parent, { fbSlug, strategy }) => {
|
||||
if (strategy === undefined) {
|
||||
strategy = defaultStrategy;
|
||||
}
|
||||
strategy.fbSlug = fbSlug;
|
||||
const newStrategy = new Strategy(strategy);
|
||||
|
||||
return new Promise((res, rej) => {
|
||||
|
||||
@@ -8,16 +8,20 @@ import { StrategyInputType } from '../types/input';
|
||||
|
||||
const args = {
|
||||
id: { type: new GraphQLNonNull(GraphQLID) },
|
||||
newStrategy: { type: new GraphQLNonNull(StrategyInputType) },
|
||||
strategy: { type: new GraphQLNonNull(StrategyInputType) },
|
||||
};
|
||||
|
||||
const resolve = (parent, { id: _id, newStrategy }) => new Promise((res, rej) => {
|
||||
const resolve = (parent, { id: _id, strategy: editedStrategy }) => new Promise((res, rej) => {
|
||||
Strategy.findOne({ _id }).exec((err, strategy) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
return;
|
||||
}
|
||||
strategy = newStrategy;
|
||||
strategy.history.push({
|
||||
updatedAt: strategy.updatedAt,
|
||||
subStrategies: strategy.subStrategies,
|
||||
});
|
||||
strategy.subStrategies = editedStrategy.subStrategies;
|
||||
strategy.save((error) => {
|
||||
if (error) {
|
||||
rej(error);
|
||||
@@ -29,7 +33,7 @@ const resolve = (parent, { id: _id, newStrategy }) => new Promise((res, rej) =>
|
||||
});
|
||||
|
||||
const mutation = {
|
||||
editParticipant: {
|
||||
editStrategy: {
|
||||
type: StrategyType,
|
||||
args,
|
||||
resolve,
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import {
|
||||
GraphQLNonNull,
|
||||
GraphQLID,
|
||||
GraphQLString,
|
||||
} from 'graphql';
|
||||
import { DatabaseError } from '../../errors';
|
||||
import { StrategyType } from '../types';
|
||||
import { Strategy } from '../../models';
|
||||
|
||||
const args = {
|
||||
fbId: { type: new GraphQLNonNull(GraphQLID) },
|
||||
fbSlug: { type: new GraphQLNonNull(GraphQLString) },
|
||||
};
|
||||
|
||||
const resolve = (parent, { fbId }) => new Promise((res, rej) => {
|
||||
Strategy.findOne({ fbId }).exec((err, strategy) => {
|
||||
const resolve = (parent, { fbSlug }) => new Promise((res, rej) => {
|
||||
Strategy.findOne({ fbSlug }).exec((err, strategy) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
return;
|
||||
}
|
||||
if (!strategy) {
|
||||
rej(new DatabaseError('None of the strategy are linked to that fbId'));
|
||||
rej(new DatabaseError('None of the strategy are linked to that fbSlug'));
|
||||
return;
|
||||
}
|
||||
res(strategy);
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
GraphQLObjectType,
|
||||
GraphQLString,
|
||||
GraphQLList,
|
||||
GraphQLBoolean,
|
||||
GraphQLID,
|
||||
} from 'graphql';
|
||||
import {
|
||||
@@ -13,10 +14,14 @@ const Type = new GraphQLObjectType({
|
||||
description: 'Everything you need to know about a strategy',
|
||||
fields: () => ({
|
||||
id: { type: GraphQLID },
|
||||
fbId: { type: GraphQLString },
|
||||
fbSlug: { type: GraphQLString },
|
||||
subStrategies: {
|
||||
args: { activeOnly: { type: GraphQLBoolean } },
|
||||
type: new GraphQLList(SubStrategyType),
|
||||
resolve(parent) {
|
||||
resolve(parent, { activeOnly }) {
|
||||
if (activeOnly) {
|
||||
return parent.subStrategies.filter(subStrategy => subStrategy.active);
|
||||
}
|
||||
return parent.subStrategies;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
GraphQLObjectType,
|
||||
GraphQLString,
|
||||
GraphQLList,
|
||||
GraphQLBoolean,
|
||||
} from 'graphql';
|
||||
import {
|
||||
EntryPointType,
|
||||
@@ -17,45 +17,46 @@ const Type = new GraphQLObjectType({
|
||||
name: 'SubStrategy',
|
||||
description: 'SubStrategy composing a strategy',
|
||||
fields: () => ({
|
||||
active: { type: GraphQLBoolean },
|
||||
name: { type: GraphQLString },
|
||||
entryPoint: {
|
||||
type: new GraphQLList(EntryPointType),
|
||||
type: EntryPointType,
|
||||
resolve(parent) {
|
||||
return parent.entryPoint;
|
||||
},
|
||||
},
|
||||
exitPoint: {
|
||||
type: new GraphQLList(ExitPointType),
|
||||
type: ExitPointType,
|
||||
resolve(parent) {
|
||||
return parent.exitPoint;
|
||||
},
|
||||
},
|
||||
sellPoint: {
|
||||
type: new GraphQLList(SellPointType),
|
||||
type: SellPointType,
|
||||
resolve(parent) {
|
||||
return parent.sellPoint;
|
||||
},
|
||||
},
|
||||
buyPoint: {
|
||||
type: new GraphQLList(BuyPointType),
|
||||
type: BuyPointType,
|
||||
resolve(parent) {
|
||||
return parent.buyPoint;
|
||||
},
|
||||
},
|
||||
stopLoss: {
|
||||
type: new GraphQLList(StopLossType),
|
||||
type: StopLossType,
|
||||
resolve(parent) {
|
||||
return parent.stopLoss;
|
||||
},
|
||||
},
|
||||
buyOrder: {
|
||||
type: new GraphQLList(BuyOrderType),
|
||||
type: BuyOrderType,
|
||||
resolve(parent) {
|
||||
return parent.buyOrder;
|
||||
},
|
||||
},
|
||||
sellOrder: {
|
||||
type: new GraphQLList(SellOrderType),
|
||||
type: SellOrderType,
|
||||
resolve(parent) {
|
||||
return parent.sellOrder;
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
GraphQLString,
|
||||
GraphQLBoolean,
|
||||
GraphQLInputObjectType,
|
||||
} from 'graphql';
|
||||
import {
|
||||
@@ -16,6 +17,7 @@ const Type = new GraphQLInputObjectType({
|
||||
name: 'SubStrategyInput',
|
||||
description: 'Payload for subStrategy input',
|
||||
fields: () => ({
|
||||
active: { type: GraphQLBoolean },
|
||||
name: { type: GraphQLString },
|
||||
entryPoint: { type: EntryPointInputType },
|
||||
exitPoint: { type: ExitPointInputType },
|
||||
|
||||
@@ -44,7 +44,7 @@ const StopLossInputType = new GraphQLInputObjectType({
|
||||
name: 'StopLossTypeInput',
|
||||
description: 'Payload for stopLossType input',
|
||||
fields: () => ({
|
||||
situations: { type: new GraphQLList(PhaseInputType) },
|
||||
phases: { type: new GraphQLList(PhaseInputType) },
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -52,7 +52,7 @@ const BuyOrderInputType = new GraphQLInputObjectType({
|
||||
name: 'BuyOrderTypeInput',
|
||||
description: 'Payload for buyOrderType input',
|
||||
fields: () => ({
|
||||
situations: { type: new GraphQLList(PhaseInputType) },
|
||||
phases: { type: new GraphQLList(PhaseInputType) },
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -60,7 +60,7 @@ const SellOrderInputType = new GraphQLInputObjectType({
|
||||
name: 'SellOrderTypeInput',
|
||||
description: 'Payload for sellOrderType input',
|
||||
fields: () => ({
|
||||
situations: { type: new GraphQLList(PhaseInputType) },
|
||||
phases: { type: new GraphQLList(PhaseInputType) },
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
/* eslint-disable max-len */
|
||||
const strategy = {
|
||||
subStrategies: [
|
||||
{
|
||||
active: true,
|
||||
name: 'Trend Following',
|
||||
entryPoint: {
|
||||
situations: [
|
||||
{
|
||||
name: 'Price Collapsing',
|
||||
conditions: [
|
||||
{
|
||||
name: '%B Moving Average going up',
|
||||
code: "percentageBandwidth.previous.direction === 'down' && percentageBandwidth.direction === 'down'",
|
||||
},
|
||||
{
|
||||
name: '%B Bandwidth going up',
|
||||
code: 'percentageBandwidth.previous.previous.bandwidth < percentageBandwidth.previous.bandwidth && percentageBandwidth.previous.bandwidth < percentageBandwidth.bandwidth',
|
||||
},
|
||||
{
|
||||
name: 'Candles Min going down',
|
||||
code: 'candle.previous.previous.min > candle.previous.min && candle.previous.min > candle.min',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
exitPoint: {
|
||||
situations: [
|
||||
{
|
||||
name: 'Market Reversing',
|
||||
conditions: [
|
||||
{
|
||||
name: 'Close above Band Moving Average',
|
||||
code: 'candle.close > bollingerBand.movingAverage',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
sellPoint: {
|
||||
situations: [
|
||||
{
|
||||
name: 'Min below lower bollingerBand.',
|
||||
conditions: [
|
||||
{
|
||||
name: '3 Candles MIN below Lower Band',
|
||||
code: 'candle.previous.previous.min < bollingerBand.previous.previous.movingAverage - bollingerBand.previous.previous.deviation && candle.previous.min < bollingerBand.previous.movingAverage - bollingerBand.previous.deviation && candle.min < bollingerBand.movingAverage - bollingerBand.deviation',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
stopLoss: {
|
||||
phases: [
|
||||
{
|
||||
name: 'Following Sell Rate',
|
||||
code: 'newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100',
|
||||
situations: [
|
||||
{
|
||||
name: 'Candle below Moving Average',
|
||||
conditions: [
|
||||
{
|
||||
name: 'Candle fully below Band Moving Average',
|
||||
code: 'candle.max < bollingerBand.movingAverage',
|
||||
},
|
||||
{
|
||||
name: 'Band Moving Average going down',
|
||||
code: "bollingerBand.direction === 'down'",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Above Bands Moving Average',
|
||||
code: 'newStopLoss = bollingerBand.movingAverage + bollingerBand.movingAverage * (stopLossPercentage - stopLossDecay) / 100',
|
||||
situations: [
|
||||
{
|
||||
name: 'Candle below Moving Average',
|
||||
conditions: [
|
||||
{
|
||||
name: 'Candle MAX below lower band',
|
||||
code: 'candle.max < bollingerBand.movingAverage - bollingerBand.deviation',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'At Bands Moving Average',
|
||||
code: 'newStopLoss = bollingerBand.movingAverage',
|
||||
situations: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
buyOrder: {
|
||||
phases: [
|
||||
{
|
||||
name: '12 times standard deviation',
|
||||
code: 'buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 12',
|
||||
situations: [
|
||||
{
|
||||
name: 'Candle cut by lower band',
|
||||
conditions: [
|
||||
{
|
||||
name: 'Max above lower band',
|
||||
code: 'candle.max > bollingerBand.movingAverage - bollingerBand.deviation',
|
||||
},
|
||||
{
|
||||
name: 'MIN below lower band',
|
||||
code: 'candle.min < bollingerBand.movingAverage - bollingerBand.deviation',
|
||||
},
|
||||
{
|
||||
name: 'Band Moving Average going down',
|
||||
code: 'bollingerBand.previous.movingAverage > bollingerBand.movingAverage',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '10 times standard deviation',
|
||||
code: 'buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 10',
|
||||
situations: [
|
||||
{
|
||||
name: '%B starting to revert',
|
||||
conditions: [
|
||||
{
|
||||
name: '%B Moving Average going up',
|
||||
code: "percentageBandwidth.direction === 'up'",
|
||||
},
|
||||
{
|
||||
name: '%B Moving Average above 0',
|
||||
code: 'percentageBandwidth.movingAverage > 0',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '4 times standard deviation',
|
||||
code: 'buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 4',
|
||||
situations: [
|
||||
{
|
||||
name: '%B going down again',
|
||||
conditions: [
|
||||
{
|
||||
name: '%B Moving Average going down',
|
||||
code: "percentageBandwidth.direction === 'down'",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '3 times standard deviation',
|
||||
code: 'buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 3',
|
||||
situations: [
|
||||
{
|
||||
name: '%B going up and above 30',
|
||||
conditions: [
|
||||
{
|
||||
name: '%B Moving Average going up',
|
||||
code: "percentageBandwidth.direction === 'up'",
|
||||
},
|
||||
{
|
||||
name: '%B Moving Average above 30',
|
||||
code: 'percentageBandwidth.movingAverage > 30',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'At lower band',
|
||||
code: 'buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation * 2',
|
||||
situations: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
active: true,
|
||||
name: 'Range Trading',
|
||||
entryPoint: {
|
||||
situations: [
|
||||
{
|
||||
name: 'Gentle Up Trend',
|
||||
conditions: [
|
||||
{
|
||||
name: 'Sub-Channel going up',
|
||||
code: "subChannel.direction === 'up'",
|
||||
},
|
||||
{
|
||||
name: 'Sub-Channel Side|Gentle|Medium',
|
||||
code: "subChannel.slope === 'Side' || subChannel.slope === 'Gentle' || subChannel.slope === 'Medium'",
|
||||
},
|
||||
{
|
||||
name: 'Candle Close above Lower Band',
|
||||
code: 'candle.close > bollingerBand.movingAverage + bollingerBand.deviation',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
exitPoint: {
|
||||
situations: [
|
||||
{
|
||||
name: 'Outside Sub-Channel',
|
||||
conditions: [
|
||||
{
|
||||
name: 'Going down or too Steep',
|
||||
code: "subChannel.direction === 'Down' || subChannel.slope === 'Steep' || subChannel.slope === 'Extreme'",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
sellPoint: {
|
||||
situations: [
|
||||
{
|
||||
name: 'Min below lower bollingerBand.',
|
||||
conditions: [
|
||||
{
|
||||
name: '%B Moving Average going down',
|
||||
code: 'percentageBandwidth.previous.movingAverage > percentageBandwidth.movingAverage',
|
||||
},
|
||||
{
|
||||
name: '%B Moving Average above 90',
|
||||
code: 'percentageBandwidth.previous.movingAverage > 90',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
stopLoss: {
|
||||
phases: [
|
||||
{
|
||||
name: 'Following Sell Rate',
|
||||
code: 'newStopLoss = sellRate + sellRate * (stopLossPercentage - stopLossDecay) / 100',
|
||||
situations: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
buyOrder: {
|
||||
phases: [
|
||||
{
|
||||
name: 'Between Band Moving Average and Lower Band',
|
||||
code: 'buyOrder = bollingerBand.movingAverage - bollingerBand.standardDeviation',
|
||||
situations: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default strategy;
|
||||
Reference in new issue
Block a user