محاكاة التداول عالية التردد مع Stream Analytics

الجمع بين لغة SQL والدالات المعرفة من قبل المستخدم JavaScript (UDFs) والتجاميع المعرفة من قبل المستخدم (UDAs) في Azure Stream Analytics يتيح للمستخدمين إجراء تحليلات متقدمة. قد تتضمن التحليلات المتقدمة التدريب على التعلم الآلي عبر الإنترنت وتسجيل النقاط، ومحاكاة العمليات ذات الحالة. هذه المقالة توضح كيفية إجراء الانحدار الخطي في وظيفة Azure Stream Analytics التي تقوم بالتدريب المستمر وتسجيل النقاط في سيناريو تداول عالي التردد.

تداول عالي التردد

التدفق المنطقي للتداول عالي التردد هو حول:

  1. الحصول على عروض أسعار في الوقت الحقيقي من تبادل الأمان.
  2. قم ببناء نموذج تنبؤي حول عروض الأسعار، حتى نتمكن من توقع حركة الأسعار.
  3. ضع أوامر الشراء أو البيع لكسب المال من التنبؤ الناجح لتحركات الأسعار.

نتيجة لذلك، نحتاج إلى:

  • موجز عروض الأسعار في الوقت الحقيقي.
  • نموذج تنبؤي يمكن أن يعمل على عروض الأسعار في الوقت الحقيقي.
  • محاكاة تداول توضح الربح أو الخسارة لخوارزمية التداول.

موجز عروض الأسعار في الوقت الحقيقي

يقدم "تبادل المستثمرين" (IEX) عروضا مجانية في الوقت الحقيقي ويسأل عن عروض الأسعار باستخدام socket.io. يمكن كتابة برنامج وحدة تحكم بسيط لتلقي عروض الأسعار في الوقت الحقيقي، ودفعها إلى مراكز أحداث Azure كمصدر بيانات. التعليمات البرمجية التالية هي هيكل البرنامج. التعليمات البرمجية تحذف معالجة الأخطاء للإيجاز. كما تحتاج إلى تضمين حزم SocketIoClientDotNet وWindowsAzure.ServiceBus NuGet في مشروعك.

using Quobject.SocketIoClientDotNet.Client;
using Microsoft.ServiceBus.Messaging;
var symbols = "msft,fb,amzn,goog";
var eventHubClient = EventHubClient.CreateFromConnectionString(connectionString, eventHubName);
var socket = IO.Socket("https://ws-api.iextrading.com/1.0/tops");
socket.On(Socket.EVENT_MESSAGE, (message) =>
{
    eventHubClient.Send(new EventData(Encoding.UTF8.GetBytes((string)message)));
});
socket.On(Socket.EVENT_CONNECT, () =>
{
    socket.Emit("subscribe", symbols);
});

فيما يلي بعض أحداث العينة التي تم إنشاؤها:

{"symbol":"MSFT","marketPercent":0.03246,"bidSize":100,"bidPrice":74.8,"askSize":300,"askPrice":74.83,volume":70572,"lastSalePrice":74.825,"lastSaleSize":100,"lastSaleTime":1506953355123,lastUpdated":1506953357170,"sector":"softwareservices","securityType":"commonstock"}
{"symbol":"GOOG","marketPercent":0.04825,"bidSize":114,"bidPrice":870,"askSize":0,"askPrice":0,volume":11240,"lastSalePrice":959.47,"lastSaleSize":60,"lastSaleTime":1506953317571,lastUpdated":1506953357633,"sector":"softwareservices","securityType":"commonstock"}
{"symbol":"MSFT","marketPercent":0.03244,"bidSize":100,"bidPrice":74.8,"askSize":100,"askPrice":74.83,volume":70572,"lastSalePrice":74.825,"lastSaleSize":100,"lastSaleTime":1506953355123,lastUpdated":1506953359118,"sector":"softwareservices","securityType":"commonstock"}
{"symbol":"FB","marketPercent":0.01211,"bidSize":100,"bidPrice":169.9,"askSize":100,"askPrice":170.67,volume":39042,"lastSalePrice":170.67,"lastSaleSize":100,"lastSaleTime":1506953351912,lastUpdated":1506953359641,"sector":"softwareservices","securityType":"commonstock"}
{"symbol":"GOOG","marketPercent":0.04795,"bidSize":100,"bidPrice":959.19,"askSize":0,"askPrice":0,volume":11240,"lastSalePrice":959.47,"lastSaleSize":60,"lastSaleTime":1506953317571,lastUpdated":1506953360949,"sector":"softwareservices","securityType":"commonstock"}
{"symbol":"FB","marketPercent":0.0121,"bidSize":100,"bidPrice":169.9,"askSize":100,"askPrice":170.7,volume":39042,"lastSalePrice":170.67,"lastSaleSize":100,"lastSaleTime":1506953351912,lastUpdated":1506953362205,"sector":"softwareservices","securityType":"commonstock"}
{"symbol":"GOOG","marketPercent":0.04795,"bidSize":114,"bidPrice":870,"askSize":0,"askPrice":0,volume":11240,"lastSalePrice":959.47,"lastSaleSize":60,"lastSaleTime":1506953317571,lastUpdated":1506953362629,"sector":"softwareservices","securityType":"commonstock"}

إشعار

الطابع الزمني للحدث هو lastUpdated، في وقت epoch.

نموذج تنبؤي للتداول عالي التردد

لهذا العرض التوضيحي، نستخدم نموذجا خطيا موصوفا في هذه الورقة.

يعد عدم توازن ترتيب الحجم (VOI) دالة على السعر الحالي/ الطلب والحجم، وسعر العرض/ الطلب وحجمه من آخر علامة. الورقة تحدد الارتباط بين VOI وحركة الأسعار المستقبلية. فهو يبني نموذجا خطيا بين قيم VOI الخمس الماضية وتغيير السعر في العلامات العشرة التالية. النموذج يتم تدريبه باستخدام بيانات اليوم السابق مع الانحدار الخطي.

ثم يتم استخدام النموذج المدرب لإجراء تنبؤات تغيير الأسعار على عروض الأسعار في يوم التداول الحالي في الوقت الحقيقي. عندما يتم التنبؤ بتغيير كبير بما يكفي للسعر، يتم تنفيذ التداول. اعتمادًا على إعداد العتبة، يمكن توقع آلاف الصفقات لسهم واحد خلال يوم التداول.

تعريف عدم توازن ترتيب الحجم

الآن، لنعبر عن عمليات التدريب والتنبؤ في وظيفة Azure Stream Analytics.

أولاً، يتم تنظيف المدخلات. يتم تحويل وقت Epoch إلى التاريخ والوقت عبر DATEADD. TRY_CAST يتم استخدامها لإكراه أنواع البيانات دون فشل الاستعلام. من الجيد دائما تحويل حقول الإدخال إلى أنواع البيانات المتوقعة، لذلك لا يوجد سلوك غير متوقع في المعالجة أو المقارنة بين الحقول.

WITH
typeconvertedquotes AS (
    /* convert all input fields to proper types */
    SELECT
        System.Timestamp AS lastUpdated,
        symbol,
        DATEADD(millisecond, CAST(lastSaleTime as bigint), '1970-01-01T00:00:00Z') AS lastSaleTime,
        TRY_CAST(bidSize as bigint) AS bidSize,
        TRY_CAST(bidPrice as float) AS bidPrice,
        TRY_CAST(askSize as bigint) AS askSize,
        TRY_CAST(askPrice as float) AS askPrice,
        TRY_CAST(volume as bigint) AS volume,
        TRY_CAST(lastSaleSize as bigint) AS lastSaleSize,
        TRY_CAST(lastSalePrice as float) AS lastSalePrice
    FROM quotes TIMESTAMP BY DATEADD(millisecond, CAST(lastUpdated as bigint), '1970-01-01T00:00:00Z')
),
timefilteredquotes AS (
    /* filter between 7am and 1pm PST, 14:00 to 20:00 UTC */
    /* clean up invalid data points */
	SELECT * FROM typeconvertedquotes
	WHERE DATEPART(hour, lastUpdated) >= 14 AND DATEPART(hour, lastUpdated) < 20 AND bidSize > 0 AND askSize > 0 AND bidPrice > 0 AND askPrice > 0
),

بعد ذلك، نستخدم الدالة LAG للحصول على قيم من علامة التجزئة الأخيرة. يتم اختيار ساعة واحدة من قيمة LIMIT DURATION بشكل عشوائي. نظرًا لتكرار عروض الأسعار، من الآمن افتراض أنه يمكنك العثور على علامة التجزئة السابقة من خلال النظر إلى الوراء ساعة واحدة.

shiftedquotes AS (
    /* get previous bid/ask price and size in order to calculate VOI */
	SELECT
		symbol,
		(bidPrice + askPrice)/2 AS midPrice,
		bidPrice,
		bidSize,
		askPrice,
		askSize,
		LAG(bidPrice) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS bidPricePrev,
		LAG(bidSize) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS bidSizePrev,
		LAG(askPrice) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS askPricePrev,
		LAG(askSize) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS askSizePrev
	FROM timefilteredquotes
),

يمكننا بعد ذلك حساب قيمة VOI. نقوم بتصفية القيم الخالية إذا لم تكن علامة التجزئة السابقة موجودة، تحسبًا لأي أمر.

currentPriceAndVOI AS (
    /* calculate VOI */
	SELECT
		symbol,
		midPrice,
		(CASE WHEN (bidPrice < bidPricePrev) THEN 0
            ELSE (CASE WHEN (bidPrice = bidPricePrev) THEN (bidSize - bidSizePrev) ELSE bidSize END)
         END) -
        (CASE WHEN (askPrice < askPricePrev) THEN askSize
            ELSE (CASE WHEN (askPrice = askPricePrev) THEN (askSize - askSizePrev) ELSE 0 END)
         END) AS VOI
	FROM shiftedquotes
	WHERE
		bidPrice IS NOT NULL AND
		bidSize IS NOT NULL AND
		askPrice IS NOT NULL AND
		askSize IS NOT NULL AND
		bidPricePrev IS NOT NULL AND
		bidSizePrev IS NOT NULL AND
		askPricePrev IS NOT NULL AND
		askSizePrev IS NOT NULL
),

الآن، نستخدم LAG مرة أخرى لإنشاء تسلسل بقيمتي VOI متتالية، متبوعة بـ 10 قيم متوسطة متتالية للسعر.

shiftedPriceAndShiftedVOI AS (
    /* get 10 future prices and 2 previous VOIs */
    SELECT
		symbol,
		midPrice AS midPrice10,
		LAG(midPrice, 1) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS midPrice9,
		LAG(midPrice, 2) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS midPrice8,
		LAG(midPrice, 3) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS midPrice7,
		LAG(midPrice, 4) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS midPrice6,
		LAG(midPrice, 5) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS midPrice5,
		LAG(midPrice, 6) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS midPrice4,
		LAG(midPrice, 7) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS midPrice3,
		LAG(midPrice, 8) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS midPrice2,
		LAG(midPrice, 9) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS midPrice1,
		LAG(midPrice, 10) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS midPrice,
		LAG(VOI, 10) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS VOI1,
		LAG(VOI, 11) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS VOI2
	FROM currentPriceAndVOI
),

ثم نعيد تشكيل البيانات في مدخلات لنموذج خطي ثنائي المتغير. مرة أخرى، نصفي الأحداث التي ليس لدينا فيها جميع البيانات.

modelInput AS (
    /* create feature vector, x being VOI, y being delta price */
	SELECT
		symbol,
		(midPrice1 + midPrice2 + midPrice3 + midPrice4 + midPrice5 + midPrice6 + midPrice7 + midPrice8 + midPrice9 + midPrice10)/10.0 - midPrice AS y,
		VOI1 AS x1,
		VOI2 AS x2
	FROM shiftedPriceAndShiftedVOI
	WHERE
		midPrice1 IS NOT NULL AND
		midPrice2 IS NOT NULL AND
		midPrice3 IS NOT NULL AND
		midPrice4 IS NOT NULL AND
		midPrice5 IS NOT NULL AND
		midPrice6 IS NOT NULL AND
		midPrice7 IS NOT NULL AND
		midPrice8 IS NOT NULL AND
		midPrice9 IS NOT NULL AND
		midPrice10 IS NOT NULL AND
		midPrice IS NOT NULL AND
		VOI1 IS NOT NULL AND
		VOI2 IS NOT NULL
),

نظرًا لأن Azure Stream Analytics لا يحتوي على دالة انحدار خطي مضمنة، فإننا نستخدم تجميعات SUMوAVG لحساب المعاملات للنموذج الخطي.

معادلة حساب الانحدار الخطي

modelagg AS (
    /* get aggregates for linear regression calculation,
     http://faculty.cas.usf.edu/mbrannick/regression/Reg2IV.html */
	SELECT
		symbol,
		SUM(x1 * x1) AS x1x1,
		SUM(x2 * x2) AS x2x2,
		SUM(x1 * y) AS x1y,
		SUM(x2 * y) AS x2y,
		SUM(x1 * x2) AS x1x2,
		AVG(y) AS avgy,
		AVG(x1) AS avgx1,
		AVG(x2) AS avgx2
	FROM modelInput
	GROUP BY symbol, TumblingWindow(hour, 24, -4)
),
modelparambs AS (
    /* calculate b1 and b2 for the linear model */
	SELECT
		symbol,
		(x2x2 * x1y - x1x2 * x2y)/(x1x1 * x2x2 - x1x2 * x1x2) AS b1,
		(x1x1 * x2y - x1x2 * x1y)/(x1x1 * x2x2 - x1x2 * x1x2) AS b2,
		avgy,
		avgx1,
		avgx2
	FROM modelagg
),
model AS (
    /* calculate a for the linear model */
	SELECT
		symbol,
		avgy - b1 * avgx1 - b2 * avgx2 AS a,
		b1,
		b2
	FROM modelparambs
),

لاستخدام نموذج اليوم السابق لتسجيل نقاط الحدث الحالي، نريد الانضمام إلى عروض الأسعار مع النموذج. ولكن بدلاً من استخدام JOIN، نحن اتحاد أحداث النموذج عرض الأسعار. ثم نستخدم LAG لإقران الأحداث بنموذج اليوم السابق، حتى نتمكن من الحصول على تطابق واحد بالضبط. بسبب عطلة نهاية الأسبوع، علينا أن ننظر إلى الوراء ثلاثة أيام. إذا استخدمنا JOIN مباشرة، فسنحصل على ثلاثة نماذج لكل حدث عرض أسعار.

shiftedVOI AS (
    /* get two consecutive VOIs */
	SELECT
		symbol,
		midPrice,
		VOI AS VOI1,		
		LAG(VOI, 1) OVER (PARTITION BY symbol LIMIT DURATION(hour, 1)) AS VOI2
	FROM currentPriceAndVOI
),
VOIAndModel AS (
    /* combine VOIs and models */
	SELECT
		'voi' AS type,
		symbol,
		midPrice,
		VOI1,
		VOI2,
        0.0 AS a,
        0.0 AS b1,
        0.0 AS b2
	FROM shiftedVOI
	UNION
	SELECT
		'model' AS type,
		symbol,
        0.0 AS midPrice,
        0 AS VOI1,
        0 AS VOI2,
		a,
		b1,
		b2
	FROM model
),
VOIANDModelJoined AS (
    /* match VOIs with the latest model within 3 days (72 hours, to take the weekend into account) */
	SELECT
		symbol,
		midPrice,
		VOI1 as x1,
		VOI2 as x2,
		LAG(a, 1) OVER (PARTITION BY symbol LIMIT DURATION(hour, 72) WHEN type = 'model') AS a,
		LAG(b1, 1) OVER (PARTITION BY symbol LIMIT DURATION(hour, 72) WHEN type = 'model') AS b1,
		LAG(b2, 1) OVER (PARTITION BY symbol LIMIT DURATION(hour, 72) WHEN type = 'model') AS b2
	FROM VOIAndModel
	WHERE type = 'voi'
),

يمكننا الآن إجراء تنبؤات وإنشاء إشارات شراء/ بيع استنادًا إلى النموذج، بقيمة عتبة 0.02. قيمة التداول 10 هي الشراء. قيمة التداول -10 هي البيع.

prediction AS (
    /* make prediction if there is a model */
	SELECT
		symbol,
		midPrice,
		a + b1 * x1 + b2 * x2 AS efpc
	FROM VOIANDModelJoined
	WHERE
		a IS NOT NULL AND
		b1 IS NOT NULL AND
		b2 IS NOT NULL AND
        x1 IS NOT NULL AND
        x2 IS NOT NULL
),
tradeSignal AS (
    /* generate buy/sell signals */
	SELECT
        DateAdd(hour, -7, System.Timestamp) AS time,
		symbol,		
		midPrice,
        efpc,
		CASE WHEN (efpc > 0.02) THEN 10 ELSE (CASE WHEN (efpc < -0.02) THEN -10 ELSE 0 END) END AS trade,
		DATETIMEFROMPARTS(DATEPART(year, System.Timestamp), DATEPART(month, System.Timestamp), DATEPART(day, System.Timestamp), 0, 0, 0, 0) as date
	FROM prediction
),

محاكاة التداول

بعد أن يكون لدينا إشارات تداول، نريد أن نختبر مدى فعالية استراتيجية التداول، دون التداول بشكل حقيقي.

نحن نحقق هذا الاختبار باستخدام UDA، مع نافذة القفز، والتنقل كل دقيقة واحدة. يسمح التجميع في التاريخ وعبارة having بالنافذة فقط لحسابات الأحداث التي تنتمي إلى نفس اليوم. بالنسبة لنافذة التنقل خلال يومين، يفصل تاريخ GROUP BY التجميع إلى اليوم السابق واليوم الحالي. عبارة HAVING تصفي النوافذ التي تنتهي في اليوم الحالي، ولكن يتم تجميعها في اليوم السابق.

simulation AS
(
    /* perform trade simulation for the past 7 hours to cover an entire trading day, and generate output every minute */
	SELECT
        DateAdd(hour, -7, System.Timestamp) AS time,
		symbol,
		date,
		uda.TradeSimulation(tradeSignal) AS s
	FROM tradeSignal
	GROUP BY HoppingWindow(minute, 420, 1), symbol, date
	Having DateDiff(day, date, time) < 1 AND DATEPART(hour, time) < 13
)

يهيئ JavaScript UDA جميع المتراكمات في الدالة init، ويحسب انتقال الحالة مع كل حدث تمت إضافته إلى النافذة، ويعيد نتائج المحاكاة في نهاية النافذة. عملية التداول العامة هي:

  • شراء الأسهم عند تلقي إشارة شراء وليس هناك مخزون عقد.
  • بيع الأسهم عند تلقي إشارة بيع وهناك الاحتفاظ بالأسهم.
  • قصيرة إذا لم يكن هناك مخزون عقد.

إذا كان هناك وضع شراء، وتم تلقي إشارة شراء، فإننا نشتري لتغطية. نحن نحتفظ بـ 10 أسهم أو نشتريها من الأسهم في هذه المحاكاة. تكلفة المعاملة مسطحة $8.

function main() {
	var TRADE_COST = 8.0;
	var SHARES = 10;
	this.init = function () {
		this.own = false;
		this.pos = 0;
		this.pnl = 0.0;
		this.tradeCosts = 0.0;
		this.buyPrice = 0.0;
		this.sellPrice = 0.0;
		this.buySize = 0;
		this.sellSize = 0;
		this.buyTotal = 0.0;
		this.sellTotal = 0.0;
	}
	this.accumulate = function (tradeSignal, timestamp) {
		if(!this.own && tradeSignal.trade == 10) {
		  // Buy to open
		  this.own = true;
		  this.pos = 1;
		  this.buyPrice = tradeSignal.midprice;
		  this.tradeCosts += TRADE_COST;
		  this.buySize += SHARES;
		  this.buyTotal += SHARES * tradeSignal.midprice;
		} else if(!this.own && tradeSignal.trade == -10) {
		  // Sell to open
		  this.own = true;
		  this.pos = -1
		  this.sellPrice = tradeSignal.midprice;
		  this.tradeCosts += TRADE_COST;
		  this.sellSize += SHARES;
		  this.sellTotal += SHARES * tradeSignal.midprice;
		} else if(this.own && this.pos == 1 && tradeSignal.trade == -10) {
		  // Sell to close
		  this.own = false;
		  this.pos = 0;
		  this.sellPrice = tradeSignal.midprice;
		  this.tradeCosts += TRADE_COST;
		  this.pnl += (this.sellPrice - this.buyPrice)*SHARES - 2*TRADE_COST;
		  this.sellSize += SHARES;
		  this.sellTotal += SHARES * tradeSignal.midprice;
		  // Sell to open
		  this.own = true;
		  this.pos = -1;
		  this.sellPrice = tradeSignal.midprice;
		  this.tradeCosts += TRADE_COST;
		  this.sellSize += SHARES;		  
		  this.sellTotal += SHARES * tradeSignal.midprice;
		} else if(this.own && this.pos == -1 && tradeSignal.trade == 10) {
		  // Buy to close
		  this.own = false;
		  this.pos = 0;
		  this.buyPrice = tradeSignal.midprice;
		  this.tradeCosts += TRADE_COST;
		  this.pnl += (this.sellPrice - this.buyPrice)*SHARES - 2*TRADE_COST;
		  this.buySize += SHARES;
		  this.buyTotal += SHARES * tradeSignal.midprice;
		  // Buy to open
		  this.own = true;
		  this.pos = 1;
		  this.buyPrice = tradeSignal.midprice;
		  this.tradeCosts += TRADE_COST;
		  this.buySize += SHARES;		  
		  this.buyTotal += SHARES * tradeSignal.midprice;
		}
	}
	this.computeResult = function () {
		var result = {
			"pnl": this.pnl,
			"buySize": this.buySize,
			"sellSize": this.sellSize,
			"buyTotal": this.buyTotal,
			"sellTotal": this.sellTotal,
			"tradeCost": this.tradeCost
			};
		return result;
	}
}

وأخيرًا، نقوم الإخراج إلى لوحة معلومات Power BI للتصور.

SELECT * INTO tradeSignalDashboard FROM tradeSignal /* output tradeSignal to PBI */
SELECT
    symbol,
    time,
    date,
    TRY_CAST(s.pnl as float) AS pnl,
    TRY_CAST(s.buySize as bigint) AS buySize,
    TRY_CAST(s.sellSize as bigint) AS sellSize,
    TRY_CAST(s.buyTotal as float) AS buyTotal,
    TRY_CAST(s.sellTotal as float) AS sellTotal
    INTO pnlDashboard
FROM simulation /* output trade simulation to PBI */

مرئيات Trades Power BI

مرئيات PNL Power BI

الملخص

يمكننا تنفيذ نموذج تداول واقعي عالي التردد مع استعلام معقد بشكل معتدل في Azure Stream Analytics. يجب علينا تبسيط النموذج من خمسة متغيرات إدخال إلى متغيرين، بسبب عدم وجود دالة انحدار خطي مضمنة. ولكن بالنسبة لمستخدم محدد، يمكن تنفيذ الخوارزميات ذات الأبعاد العالية والرقي كـ JavaScript UDA أيضًا.

تجدر الإشارة إلى أنه يمكن اختبار معظم الاستعلام، بخلاف JavaScript UDA، وتصحيح الأخطاء في Visual Studio من خلال أدوات Azure Stream Analytics لـ Visual Studio. بعد كتابة الاستعلام الأولي، قضى الكاتب أقل من 30 دقيقة في اختبار الاستعلام وتصحيحه في Visual Studio.

حاليا، لا يمكن تصحيح أخطاء UDA في Visual Studio. نحن نعمل على تمكين ذلك مع القدرة على التنقل عبر التعليمات البرمجية ل JavaScript. بالإضافة إلى ذلك، تحتوي الحقول التي تصل إلى UDA على أسماء صغيرة. لم يكن سلوكا واضحا أثناء اختبار الاستعلام. ولكن مع مستوى توافق Azure Stream Analytics 1.1، نحافظ على غلاف اسم الحقل بحيث يكون السلوك أكثر طبيعية.

آمل أن تكون هذه المقالة بمثابة مصدر إلهام لجميع مستخدمي Azure Stream Analytics، الذين يمكنهم استخدام خدمتنا لإجراء تحليلات متقدمة في الوقت الفعلي تقريبا، بشكل مستمر. أخبرنا بأي ملاحظات لديك لتسهيل تنفيذ الاستعلامات لسيناريوهات التحليلات المتقدمة.