Merge pull request #10 from Superalgos/develop

Merge develop to master for production
This commit is contained in:
Barry Low authored and GitHub committed 2019-04-12 09:53:07 +02:00
commit df895e9552
9 files changed
+598 -142

No files matched your search

+294 -119
View File
@@ -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);
+11 -1
View File
@@ -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 -4
View File
@@ -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,
+5 -5
View File
@@ -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);
+7 -2
View File
@@ -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;
},
},
+9 -8
View File
@@ -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;
},
+2
View File
@@ -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 },
+3 -3
View File
@@ -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) },
}),
});
+259
View File
@@ -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;