MQL4 WebRequest POST Json 到 Django API 使用 Django rest 框架,在主体末尾获取 \x00

MQL4 WebRequest POST Json to Django API using Django rest framework, getting \x00 at the end of body

我只用了几个星期的 Django,所以可能会有一些错误。

我有一个使用 Django rest 框架的 API,它似乎运行良好。 使用 postman 一切正常

我使用 Mql4 中的 WebRequest 将数据发送到 api

string data = "{ ... }“; 
char post_data[];
post_data = StringToCharArray(data, post_data, WHOLE_ARRAY);
int r = WebRequest("POST", "http://127.0.0.1/api/symbol/","Content-Type: application/json",5000, data,res_data, res_headers);

给WebRequest的数据没问题,但是函数在body的末尾添加了\x00。

这是我的 post 到达 Django 休息框架时的数据

{'Content-Length': '982', 'Content-Type': 'application/json', 'Accept': 'image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*', 'Host': '127.0.0.1', 'Accept-Language': 'fr,en', 'Accept-Charset': '*,utf-8', 'Connection': 'Keep-Alive', 'Proxy-Connection': 'Keep-Alive', 'Pragma': 'no-cache', 'Cache-Control': 'no-cache', 'User-Agent': 'MetaTrader 4 Terminal/4.1353 (Windows NT 6.1; x86)'}
b'{"name": "GOLDs","date_market": "2022-02-01T00:00:00.000000Z","period": "M1","open_price": 1797.64,"close_price": 1870.91,"low_price": 1788.33,"high_price": 1879.12,"bollinger_band":[{"period":"M1","moving_average_period":20,"standard_deviation":1.5,"high":1936.06829,"low":1717.61271,"moving_average":1826.8405},{"period":"M1","moving_average_period":20,"standard_deviation":2,"high":1972.47755,"low":1681.20345,"moving_average":1826.8405},{"period":"M1","moving_average_period":20,"standard_deviation":2.5,"high":2008.88681,"low":1644.79419,"moving_average":1826.8405}],"moving_average":[{"period":"M1","moving_average_period":50,"type": "0","value":1569.6854},{"period":"M1","moving_average_period":100,"type": "0","value":1399.8002},{"period":"M1","moving_average_period":200,"type": "0","value":1245.38985}],"MACD_zerolag":[{"period":"M1","fast_EMA_period":12,"slow_EMA_period":26,"signal_EMA_period":9,"histogram_value":-0.01794,"signal_value":0.09465,"MACD_value":0.07671}]}\x00'

所以我得到以下错误:

POST /api/symbol/ - 400
{'Content-Type': 'application/json', 'Vary': 'Accept', 'Allow': 'GET, POST, HEAD, OPTIONS'}
b'{"detail":"JSON parse error - Extra data: line 1 column 982 (char 981)"}'

如果使用 Postman 发送相同的数据删除 \x00 一切顺利。

mql4 客户端配置错误吗?

或者我可以删除接收到的数据来删除这个 \x00 吗?

这是我的 models.py

    from django.db import models, transaction

M1 = 'M1'
M5 = 'M5'
M15 = 'M15'
M30 = 'M30'
H1 = 'H1'
H4 = 'H4'
DAILY = 'DAILY'
WEEKLY = 'WEEKLY'
MONTHLY = 'MONTHLY'

PERIOD_CHOICES = (
    (M1, 'Une minute'),
    (M5, 'Cinq minutes'),
    (M15, 'Quinze minutes'),
    (M30, 'Trente minutes'),
    (H1, 'Une heure'),
    (H4, 'Quatre heures'),
    (DAILY, 'Journalier'),
    (WEEKLY, 'Hebdomadaire'),
    (MONTHLY, 'Mensuel'),
)


class BollingerBand(models.Model):

    period = models.CharField(max_length=30, choices=PERIOD_CHOICES, verbose_name='Période')
    moving_average_period = models.CharField(max_length=8)
    standard_deviation = models.DecimalField(max_digits=6, decimal_places=2)

    symbol = models.ForeignKey('API.Symbol', on_delete=models.CASCADE, related_name='bollinger_band', default=1)

    high = models.DecimalField(max_digits=12, decimal_places=6)
    low = models.DecimalField(max_digits=12, decimal_places=6)
    moving_average = models.DecimalField(max_digits=12, decimal_places=6)



class MovingAverage(models.Model):

    period = models.CharField(max_length=30, choices=PERIOD_CHOICES, verbose_name='Période')
    moving_average_period = models.CharField(max_length=8)
    type = models.TextField(max_length=30)

    symbol = models.ForeignKey('API.Symbol', on_delete=models.CASCADE, related_name='moving_average', default=1)

    value = models.DecimalField(max_digits=12, decimal_places=6)




class MACDZR(models.Model):

    period = models.CharField(max_length=30, choices=PERIOD_CHOICES, verbose_name='Période')
    fast_EMA_period = models.CharField(max_length=4)
    slow_EMA_period = models.CharField(max_length=4)
    signal_EMA_period = models.CharField(max_length=4)

    symbol = models.ForeignKey('API.Symbol', on_delete=models.CASCADE, related_name='MACD_zerolag', default=1)

    histogram_value = models.DecimalField(max_digits=12, decimal_places=6)
    signal_value = models.DecimalField(max_digits=12, decimal_places=6)
    MACD_value = models.DecimalField(max_digits=12, decimal_places=6)





class Symbol(models.Model):


    name = models.CharField(max_length=30, default='undefined')
    date_created = models.DateTimeField(auto_now_add=True)
    date_updated = models.DateTimeField(auto_now=True)

    date_market = models.DateTimeField()

    period = models.CharField(max_length=30, choices=PERIOD_CHOICES, verbose_name='Période')

    open_price = models.DecimalField(max_digits=12, decimal_places=6)
    close_price = models.DecimalField(max_digits=12, decimal_places=6)
    high_price = models.DecimalField(max_digits=12, decimal_places=6)
    low_price = models.DecimalField(max_digits=12, decimal_places=6)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['name', 'date_market', 'period'],
                name='unique_symbol'
            )
        ]

    def __str__(self):
        return self.name

Serializers.py

from rest_framework import serializers

from API.models import Symbol, BollingerBand, MACDZR, MovingAverage


class BollingerBandSerializer(serializers.ModelSerializer):

    class Meta:
        model = BollingerBand
        fields = ['period',
                  'moving_average_period',
                  'standard_deviation',
                  'symbol',
                  'high',
                  'low',
                  'moving_average']



class MovingAverageSerializer(serializers.ModelSerializer):

    class Meta:
        model = MovingAverage
        fields = ['period',
                  'moving_average_period',
                  'type',
                  'symbol',
                  'value']



class MACDZRSerializer(serializers.ModelSerializer):

    class Meta:
        model = MACDZR
        fields = ['period',
                  'fast_EMA_period',
                  'slow_EMA_period',
                  'signal_EMA_period',
                  'symbol',
                  'histogram_value',
                  'signal_value',
                  'MACD_value']



class SymbolSerializer(serializers.ModelSerializer):

    bollinger_band = BollingerBandSerializer(many=True)
    moving_average = MovingAverageSerializer(many=True)
    MACD_zerolag = MACDZRSerializer(many=True)

    class Meta:
        model = Symbol
        fields = ['id',
                  'name',
                  'date_created',
                  'date_updated',
                  'date_market',
                  'period',
                  'open_price',
                  'close_price',
                  'high_price',
                  'low_price',
                  'bollinger_band',
                  'moving_average',
                  'MACD_zerolag'
                  ]


    def create(self, validated_data):

        bollinger_bands_data = validated_data.pop('bollinger_band')
        moving_averages_data = validated_data.pop('moving_average')
        MACDs_zerolag_data = validated_data.pop('MACD_zerolag')

        symbol = Symbol.objects.create(**validated_data)

        for bollinger_band_data in bollinger_bands_data:
            BollingerBand.objects.create(symbol=symbol, **bollinger_band_data)

        for MACD_zerolag_data in MACDs_zerolag_data:
            MACDZR.objects.create(symbol=symbol, **MACD_zerolag_data)

        for moving_average_data in moving_averages_data:
            MovingAverage.objects.create(symbol=symbol, **moving_average_data)

        return symbol

和settings.py

"""
Django settings for trading_project project.

Generated by 'django-admin startproject' using Django 4.0.2.

For more information on this file, see
https://docs.djangoproject.com/en/4.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.0/ref/settings/
"""

from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-)6f&ci7@)t96(k^7am%66@%e%(88a%u00+3h5a13s461#q7dqm'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = [
    '0.0.0.0',
    '127.0.0.1',
]


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    #'django.contrib.sites',
    'rest_framework',
    'authentication',
    'API',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'request_logging.middleware.LoggingMiddleware',
]

ROOT_URLCONF = 'trading_project.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(BASE_DIR, 'templates/'),
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'trading_project.wsgi.application'


# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'trading_project',
        'USER': 'admin',
        'PASSWORD': 'testpassword',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}


# Password validation
# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/

LANGUAGE_CODE = 'fr-fr'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/

STATIC_URL = 'static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

AUTH_USER_MODEL = 'authentication.User'
LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'home'
LOGOUT_URL = 'logout'
LOGOUT_REDIRECT_URL = 'login'


LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.request': {
            'handlers': ['console'],
            'level': 'DEBUG',  # change debug level as appropiate
            'propagate': False,
        },
    },
}

如果有人对此有简单的解决方案 谢谢

我找到了我的解决方案, 当我将数据字符串转换为 post_Data 对象时,长度不是 WHOLE_ARRAY,而是 StringLen.

StringToCharArray(data, post_data,0, StringLen(data));