English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
インターネットを介して端末間でデータ交換をするためのWinInet.dll利用

インターネットを介して端末間でデータ交換をするためのWinInet.dll利用

MetaTrader 5統合 | 28 10月 2015, 13:12
4 106 0
---
---

蓄積されている数多くの新しいユーザーインターフェース要素を用いて、MetaTrader 5 はユーザーにまたとないチャンスの扉を開きます。これにより以前には利用できなかった関数がいまや最大限に活用できるのです。

このレッスンで学習することは以下です。

  • 基本的なインターネット技術を使用する。
  • サーバーを介して端末間でデータ交換を行う。
  • MQL5 環境でインターネットと連携するための遺伝的ライブラリ クラスを作成する。

MQL5 CodeBase にはスクリプトの例が含まれています。それは wininet.dll ライブラリと連動し、サーバーページリクエストの例を表示します。ただ、ここではもっと先まで進み、ページをもたらすだけでなく、リクエストをする他の端末に対して後の転送用データを送信し格納 するサーバー作成まで行います。

注意:PHPで構成されているためサーバーにアクセスできない方は Denwer キットをダウンロードし、それをワーキング プラットフォームとして使用するとよいでしょう。また、検証用にはローカルホストで Apache サーバーおよび PHP の使用を推奨します。

サーバーにいずれのリクエストを送信するにも、ライブラリの主要関数7個が必要となります。

InternetAttemptConnect  インターネット接続セットと接続成立を試みます。
InternetOpen
WinInet ライブラリ関数の動作へのストラクチャを初期化します。この関数はライブラリのその他あらゆる関数を起動する前に起動する必要があります。
InternetConnect HTTP URL または FTPのアドレスによって指定されたリソースを開きます。オープン接続に記述を返します。
HttpOpenRequest 接続設定用 HTTP リクエストに対して記述を作成します。
HttpSendRequest 作成されたディスクリプタを使用してクエリーを送信します。
InternetReadFile クエリーが処理されたあとサーバーから受け取られたデータを読みます。
InternetCloseHandle 転送されたディスクリプタを解放します。

 
関数の詳述およびパラメータは MSDN ヘルプシステムにあります。

関数の宣言は MQL4でのものと同様ですが、ユニコード呼び出しとリンクによる行変換は異なります。

#import "wininet.dll"
int InternetAttemptConnect(int x);
int InternetOpenW(string &sAgent,int lAccessType,string &sProxyName,string &sProxyBypass,int lFlags);
int InternetConnectW(int hInternet,string &szServerName,int nServerPort,string &lpszUsername,string &lpszPassword,int dwService,int dwFlags,int dwContext);
int HttpOpenRequestW(int hConnect,string &Verb,string &ObjectName,string &Version,string &Referer,string &AcceptTypes,uint dwFlags,int dwContext);
int HttpSendRequestW(int hRequest,string &lpszHeaders,int dwHeadersLength,uchar &lpOptional[],int dwOptionalLength);
int HttpQueryInfoW(int hRequest,int dwInfoLevel,int &lpvBuffer[],int &lpdwBufferLength,int &lpdwIndex);
int InternetReadFile(int hFile,uchar &sBuffer[],int lNumBytesToRead,int &lNumberOfBytesRead);
int InternetCloseHandle(int hInet);
#import

//To make it clear, we will use the constant names from wininet.h.
#define OPEN_TYPE_PRECONFIG     0           // use the configuration by default
#define FLAG_KEEP_CONNECTION    0x00400000  // do not terminate the connection
#define FLAG_PRAGMA_NOCACHE     0x00000100  // no cashing of the page
#define FLAG_RELOAD             0x80000000  // receive the page from the server when accessing it
#define SERVICE_HTTP            3           // the required protocol

フラグの詳述およびパラメータは MSDN の関数詳述と同じ項にあります。その他定数および関数の宣言を確認したければ、本稿添付の原ファイル wininet.h をダウンロードすることができます。

1. インターネットセッションの作成および削除に関するガイド

まず最初にすることはセッションを作成しホストへの接続をオープンすることです。セッションはプログラム初期化中には一度だけ作成することが望ましいとされています(たとえば OnInit 関数内で)。または Expert Advisor 起動の一番最初に行うことも可能ですが、重要なことはセッションのクローズ前に一度だけ問題なくかならずそれを作成することです。また、 OnStart OnTimer を実装するループで毎回繰り返し行ったり不必要に行うことはしません。頻繁な呼び出しや各呼び出しに必要なストラクチャを作成することを避けるのが重要です。

そのため、セッションの記述と接続ディスクリプタに対してはグローバルクラスインスタンスを一度だけ使用します。

   string            Host;       // host name
   int               Port;       // port
   int               Session;    // session descriptor
   int               Connect;    // connection descriptor

bool MqlNet::Open(string aHost,int aPort)
  {
   if(aHost=="")
     {
      Print("-Host is not specified");
      return(false);
     }
   // checking the DLL resolution in the terminal  
   if(!TerminalInfoInteger(TERMINAL_DLLS_ALLOWED))
     {
      Print("-DLL is not allowed");
      return(false);
     }
   // if the session was identifies, then we close
   if(Session>0 || Connect>0) Close();
   // record of attempting to open into the journal
   Print("+Open Inet...");
   // if we were not able to check for the presence of an Internet connection, then we exit
   if(InternetAttemptConnect(0)!=0)
     {
      Print("-Err AttemptConnect");
      return(false);
     }
   string UserAgent="Mozilla"; string nill="";
   // open a session
   Session=InternetOpenW(UserAgent,OPEN_TYPE_PRECONFIG,nill,nill,0);
   // if we were not able to open a session, then exit
   if(Session<=0)
     {
      Print("-Err create Session");
      Close();
      return(false);
     }
   Connect=InternetConnectW(Session,aHost,aPort,nill,nill,SERVICE_HTTP,0,0);
   if(Connect<=0)
     {
      Print("-Err create Connect");
      Close();
      return(false);
     }
   Host=aHost; Port=aPort;
   // otherwise all attempts were successful
   return(true);
  }

初期化後、ディスクリプタ Session  および Connect は続く関数すべてで使用可能です。作業がすべて完了し、MQL プログラムがアンインストールされたら、それらは消去する必要があります。これは InternetCloseHandle 関数を用いて行います。

void MqlNet::CloseInet()
  {
   Print("-Close Inet...");
   if(Session>0) InternetCloseHandle(Session); Session=-1;
   if(Connect>0) InternetCloseHandle(Connect); Connect=-1;
  }

注意! インターネット関数に連動する際は、InternetCloseHandle を用いてそれらによって駆動されるディスクリプタをすべて解放する必要があります。

2. サーバーに対するリクエスト送信およびページ受け取り

リクエストを送信し、そのリクエストに対する回答を受け取るには関数があと3つ必要です。それらは、HttpOpenRequestHttpSendRequest InternetReadFileです。リクエストに対する回答ページを受け取る最重要点は基本的にそのコンテンツをローカルファイルに保存するシンプルな手続きです。


リクエストとコンテンツの作業がしやすいように汎用関数を2つ作成します。

リクエスト送信

bool MqlNet::Request(string Verb,string Object,string &Out,bool toFile=false,string addData="",bool fromFile=false)
  {
   if(toFile && Out=="")
     {
      Print("-File is not specified ");
      return(false);
     }
   uchar data[];
   int hRequest,hSend,h;
   string Vers="HTTP/1.1";
   string nill="";
   if(fromFile)
     {
      if(FileToArray(addData,data)<0)
        {
         Print("-Err reading file "+addData);

         return(false);
        }
     } // read file in the array
   else StringToCharArray(addData,data);

   if(Session<=0 || Connect<=0)
     {
      Close();
      if(!Open(Host,Port))
        {
         Print("-Err Connect");
         Close();
         return(false);
        }
     }
   // create a request descriptor
   hRequest=HttpOpenRequestW(Connect,Verb,Object,Vers,nill,nill,FLAG_KEEP_CONNECTION|FLAG_RELOAD|FLAG_PRAGMA_NOCACHE,0);
   if(hRequest<=0)
     {
      Print("-Err OpenRequest");
      InternetCloseHandle(Connect);
      return(false);
     }
   // send request
   // headline for request
   string head="Content-Type: application/x-www-form-urlencoded";
   // sent file
   hSend=HttpSendRequestW(hRequest,head,StringLen(head),data,ArraySize(data)-1);
   if(hSend<=0)
     {
      Print("-Err SendRequest");
      InternetCloseHandle(hRequest);
      Close();
     }
   // read the page 
   ReadPage(hRequest,Out,toFile);
   // close all handles
   InternetCloseHandle(hRequest); 
   InternetCloseHandle(hSend);
   return(true);
  }

MqlNet:: Request の関数パラメータ

  • string Verb – リクエストタイプ “GET” または “POST”
  • string Object – パラメータで渡されるページ名
  • string &Out – 回答が受け取られる行
  • bool toFile – toFile=trueならば Out は回答が受け取られるファイル名を示します。
  • string addData - 追加データ
  • bool fromFile - fromFile = trueならば addData は送信する必要のあるファイル名

受け取られるディスクリプタのコンテンツ読み出し

void MqlNet::ReadPage(int hRequest,string &Out,bool toFile)
  {
   // read the page 
   uchar ch[100];
   string toStr="";
   int dwBytes,h;
   while(InternetReadFile(hRequest,ch,100,dwBytes))
     {
      if(dwBytes<=0) break;
      toStr=toStr+CharArrayToString(ch,0,dwBytes);
     }
   if(toFile)
     {
      h=FileOpen(Out,FILE_BIN|FILE_WRITE);
      FileWriteString(h,toStr);
      FileClose(h);
     }
   else Out=toStr;
  }

MqlNet:: ReadPage関数パラメータ

  • Int hRequest - リクエストディスクリプタ。ここからデータが読まれます。
  • string &Out – 回答が受け取られる行
  • bool toFile - toFile = trueならば Out は回答が受け取られるファイル名をです。

これらをすべて一つにまとめると、インターネットと連携する MqlNet ライブラリクラスを取得します。

class MqlNet
  {
   string            Host;     // host name
   int               Port;     // port
   int               Session; // session descriptor
   int               Connect; // connection descriptor
public:
                     MqlNet(); // class constructor
                    ~MqlNet(); // destructor
   bool              Open(string aHost,int aPort); // create a session and open a connection
   void              Close(); // close session and connection
   bool              Request(string Verb,string Request,string &Out,bool toFile=false,string addData="",bool fromFile=false); // send request
   bool              OpenURL(string URL,string &Out,bool toFile); // somply read the page into the file or the variable
   void              ReadPage(int hRequest,string &Out,bool toFile); // read the page
   int               FileToArray(string FileName,uchar &data[]); // copy the file into the array for sending
  };

それは基本的にインターネットと連携するための多様なニーズを満たすであろう必要なすべての関数です。その使用例を考察します。

例1 MQLプログラムの端末フォルダへの 自動ダウンロードMetaGrabber スクリプト

クラス動作検証を始めるにあたりもっとも簡単なタスクから始めます。それはページを読み、そのコンテンツを指定フォルダーに保存することです。ただしページをただ単に読むことはあまり面白いものではなさそうです。よってスクリプトの動作から何かを得るために、そこにサイトからの mql プログラムのグラバー機能を割り当てます。MetaGrabber スクリプトのタスクは以下です。

  • URL 分析およびホスト、リクエスト、ファイル名への分離
  • ホストへのリクエスト送信、受け取り、端末フォルダー\\ Filesへのファイル保存
  • それの「ファイル」から要求されたデータフォルダへの移動
    \Experts, \Indicators, \Scripts, \Include, \Libraries, \Tester(set), \Templates.

二番目の問題解決には MqlNet クラスを使用します。三番目のタスクには Kernel32.dllからの関 数MoveFileEx を使用します。

#import "Kernel32.dll"
bool MoveFileExW(string &lpExistingFileName, string &lpNewFileName, int dwFlags);
#import "Kernel32.dll"

最初の課題に対して URL 行をパースする短いサービス関数を作成します。

アドレスから3行を割り当てる必要があります。それはホスト、サイトへのパス、ファイル名です。
たとえば行 http://www.mysite.com/folder/page.html では以下のように行います。

- ホスト = www.mysite.com
- リクエスト = / folder / page.html
- ファイル名 = page.html

MQL5 サイトの CodeBase の場合は、パスウェイ は同じストラクチャをしています。たとえばページ https://www.mql5.com/ru/code/79 looks like http://p.mql5.com/data/18/79/ErrorDescription.mqh のライブラリ ErrorDescription.mq5 へのパスです。このパスはリンクを右クリックし『リンクをコピーする』を選択するだけで簡単に取得されます。よってURL は2つに分割されます。一つはリクエスト用、もう一つはファイル格納をしやすくするファイル名用です。

- ホスト = p.mql5.com
- リクエスト = / data/18/79/5/ErrorDescription.mqh
- ファイル名 = ErrorDescription.mqh

これは次の関数 ParseURL が扱う一種のラインパースです。

void ParseURL(string path,string &host,string &request,string &filename)
  {
   host=StringSubstr(URL,7);
   // removed
   int i=StringFind(host,"/"); 
   request=StringSubstr(host,i);
   host=StringSubstr(host,0,i);
   string file="";
   for(i=StringLen(URL)-1; i>=0; i--)
      if(StringSubstr(URL,i,1)=="/")
        {
         file=StringSubstr(URL,i+1);
         break;
        }
   if(file!="") filename=file;
  }

スクリプトの外部パラメータではパラメータを2つだけ作成します。 URL(mql5 ファイルのパス)とそれに続く配置のフォルダータイプです。これはパスをセットしたい端末フォルダです。

そして取得するのが、短いですがひじょうに有用な以下のようなスクリプトです。

//+------------------------------------------------------------------+
//|                                                  MetaGrabber.mq5 |
//|                                 Copyright © 2010 www.fxmaster.de |
//|                                         Coding by Sergeev Alexey |
//+------------------------------------------------------------------+
#property copyright "www.fxmaster.de  © 2010"
#property link      "www.fxmaster.de"
#property version               "1.00"
#property description  "Download files from internet"

#property script_show_inputs

#include <InternetLib.mqh>

#import "Kernel32.dll"
bool MoveFileExW(string &lpExistingFileName,string &lpNewFileName,int dwFlags);
#import
#define MOVEFILE_REPLACE_EXISTING 0x1

enum _FolderType
  {
   Experts=0,
   Indicators=1,
   Scripts=2,
   Include=3,
   Libraries=4,
   Files=5,
   Templates=6,
   TesterSet=7
  };

input string URL="";
input _FolderType FolderType=0;
//------------------------------------------------------------------ OnStart
int OnStart()
  {
   MqlNet INet; // variable for working in the Internet
   string Host,Request,FileName="Recieve_"+TimeToString(TimeCurrent())+".mq5";

   // parse url
   ParseURL(URL,Host,Request,FileName);

   // open session
   if(!INet.Open(Host,80)) return(0);
   Print("+Copy "+FileName+" from  http://"+Host+" to "+GetFolder(FolderType));

   // obtained file
   if(!INet.Request("GET",Request,FileName,true))
     {
      Print("-Err download "+URL);
      return(0);
     }
   Print("+Ok download "+FileName);

   // move to the target folder
   string to,from,dir;
   // if there is no need to move it elsewhere
   if(FolderType==Files) return(0);

   // from
   from=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\"+FileName;

   // to
   to=TerminalInfoString(TERMINAL_DATA_PATH)+"\\";
   if(FolderType!=Templates && FolderType!=TesterSet) to+="MQL5\\";
   to+=GetFolder(FolderType)+"\\"+FileName;

   // move file 
   if(!MoveFileExW(from,to,MOVEFILE_REPLACE_EXISTING))
     {
      Print("-Err move to "+to);
      return(0);
     }
   Print("+Ok move "+FileName+" to "+GetFolder(FolderType));

   return(0);
  }
//------------------------------------------------------------------ GetFolder
string GetFolder(_FolderType foldertype)
  {
   if(foldertype==Experts) return("Experts");
   if(foldertype==Indicators) return("Indicators");
   if(foldertype==Scripts) return("Scripts");
   if(foldertype==Include) return("Include");
   if(foldertype==Libraries) return("Libraries");
   if(foldertype==Files) return("Files");
   if(foldertype==Templates) return("Profiles\\Templates");
   if(foldertype==TesterSet) return("Tester");
   return("");
  }
//------------------------------------------------------------------ ParseURL
void ParseURL(string path,string &host,string &request,string &filename)
  {
   host=StringSubstr(URL,7);
   // removed
   int i=StringFind(host,"/"); 
   request=StringSubstr(host,i);
   host=StringSubstr(host,0,i);
   string file="";
   for(i=StringLen(URL)-1; i>=0; i--)
      if(StringSubstr(URL,i,1)=="/")
        {
         file=StringSubstr(URL,i+1);
         break;
        }
   if(file!="") filename=file;
  }
//+------------------------------------------------------------------+


お気に入りのセクション https://www.mql5.com/en/code について実験をします。ダウンロードされたファイルはすぐにエディタのナビゲータに表示されます。それらは端末またはエディタを再起動しなくてもコンパイル可能です。ファイルの移動先として望ましいフォルダを検索するファイルシステムの長いパスをさまようことはありません。

注意!数多くのサイトは大量のコンテントをダウンロードすることに対してセキュリティを設定しています。そのような大量ダウンロードの場合は、みなさんの IPアドレスがこのリソースによりブロックされる可能性があります。よって頻繁に利用し使用を禁じされたくないリソースからファイルの『マシン』ダウンロードを利用する際は最新の注意を払ってください。

提案のサービスを改良してさらに一歩踏み込みたい方は、クリップボードコンテンツのインターセプションとそれ以上の自動ダウンロードを持つ Clipboard スクリプトの利用が可能です。

例2 単一チャート上で複数仲介会社からのクオート監視

というわけでインターネットからファイルを取得する方法は学習しました。そこでもっと興味深い課題を考察します。サーバー上でのこのデータの送信および格納方法です。これを行うには、短い PHPスクリプトが必要です。それをサーバーにセットします。すでに書かれた MqlNet クラスを利用して監視 MetaArbitrage 用 Expert Advisor を作成します。PHPスクリプトと連動したエキスパートのタスクは次のようなものです。

  • サーバーに Expert Advisor のリクエストを送信
  • サーバー上に解答ページ(PHP)を作成
  • Expert Advisorによるこのページの受け取り
  • その分析および画面への結果配信

MQLモジュールと PHPスクリプト間の連携についてのスキーム図を以下に示します。


これら課題を解決するために MqlNet クラスを使います。

データの重複を避けるため、また古いクオートを排除するため、おもなパラメータを4つ送信します。仲介会社のサーバー名(現在価格のソース)、通貨、価格、UTCにおけるクオート時刻です。たとえば、弊社のリソースからのスクリプトへのアクセス リクエストは以下のようなものです。q

www.fxmaster.de/metaarbitr.php?server=Metaquotes&pair=EURUSD&bid=1.4512&time=13286794

これらパラメータと実際のクオートがサーバーに格納され、該当通貨のその他格納されたクオートすべてと共に回答ページで公表されます。

この交換の『付加的な』利便性はクオートが MT5 同様 MT4 からも送信することができることです!

サーバーによって作成されるページは通常の CSV ファイルです。このスクリプトではそれは以下のように記述されます。

ServerName1; Bid1; Time1
ServerName 2; Bid2; Time2
ServerName 3; Bid3; Time3

ServerName N; BidN; TimeN

またご自身の別パラメータをそれに追加することも可能です(たとえばサーバータイプでデモまたは実際の)。この CSV ファイルを格納し、値のテーブルおよび画面に表示される価格行のアウトプットで一行ずつパースします。

このファイル処理は、それぞれ特殊なケースで要求されるものを選択し多くの異なる方法で行うことが可能です。たとえば MetaTrader 4 デモサーバーから受け取られたクオートを除外する、などです。


インターネットサーバーを利用するメリットは明白です。みなさんはご自身のクオートを送信し、それを別のトレーダーが受信し閲覧することができるのです。同様に他のトレーダーが送信したクオートをみなさんも受信するのです。それは、端末間相互交流が両側で行われる、データ交換が以下のスキームで示されるように行われる、ということです。


このスキームはあらゆる端末数間での情報交換の原則に対する基盤の役割を果たします。注釈付の完全な MetaArbitrage Expert Advisor と PHPスクリプトは本稿添付のリンクからダウンロードすることができます。PHP利用関数についてさらなる内容はサイ トphp.su で読むことができます。

例3 端末内でのメッセージ交換(ミニチャット)MetaChat Expert Advisor

トレーディングや数字から一歩離れ、端末を終了することなく同時に複数の人とチャットできるアプリケーションを作成します。このためにはもう一つ PHP スクリプトが必要です。それは通常前に作成したものとひじょうに似通ったものです。ただしこのスクリプトで時刻引用を分析する代わりにファイルの行数を分析する点は例外です。Expert Advisor のタスクは次のようなものです。

  • サーバーへのテキスト送信
  • この行の共通ファイルへの追加、ファイルサイズ管理、回答ファイル(php)作成
  • 進行中チャット受け取りおよびその画面への表示

MetaChat の動作は以前の Expert Advisorのそれとは異なります。原理、シンプルなアウトプット用CSV ファイルは同じです。


MetaChat および MetaArbitrage 開発者のサイトに保管されています。それらの動作用PHPスクリプトも同じ場所に保管されています。
よって動作検証を行ったりこのサービスを利用したい場合は、以下のリンクからそこにアクセスできます。
MetaСhat - www.fxmaster.de/metachat.php
MetaArbitrage - www.fxmaster.de/metaarbitr.php

おわりに

これでHTTPリクエストに関してよく理解しました。インターネットを通じてデータ送受信をし、またいっそう快適に作業手順を組み立てる技能を得ました。しかしどんな機能もつねに改善の可能性があるものです。以下はそれら改善の新しい潜在的な改善方向と考えることができます。

  • Expert Advisors 分析のためのニュースを読みその他の情報を端末に直接受信すること
  • Expert Advisors の遠隔管理
  • Expert Advisors またはインディケータの自動更新
  • トレードのコピー機能、解釈機能、シグナル送信
  • Expert Advisors 用 lights および set-files とともにテンプレートのダウンロード
  • などなどです。

本稿ではリクエストの GET タイプを使用しました。サーバー分析のために少数のパラメータを伴ってファイル取得、リクエスト送信が必要なとき、それは十分にタスクを達成します。

次のレッスンでは POST リクエストを細かく見ていきます。それはサーバーへのファイル送信または端末間でのファイル共有を行うものです。そしてその利用例を考察します。

有用な情報リソース

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/73

添付されたファイル |
internetlib.mqh (8.35 KB)
metaarbitrage.mq5 (9.27 KB)
metachat.mq5 (5.68 KB)
metagrabber.mq5 (3.24 KB)
metaarbitr.zip (0.72 KB)
wininet.zip (12.81 KB)
MQL5 コード用自動作成ドキュメンテーション MQL5 コード用自動作成ドキュメンテーション
Java プログラマーの多くは JavaDocs により作成することのできる自動作成ドキュメンテーションを熟知されていることと思います。その考え方は、検索が簡単なヘルプファイルに抽出できる半構造法によりコードにコメントを追加するというものです。C++ 言語界にもまたドキュメンテーション自動作成機能があります。 Microsoft の SandCastle と Doxygen が代表的な2つです。本稿は MQL5 コードで構成済みコメントから HTML ヘルプファイルを作成するための Doxygen 使用について述べます。実験はひじょうにうまくいきましたから、Doxygen が MQL5 コードから作り出すヘルプのドキュメンテーションは大きな価値を加えると信じています。
MQL5およびMQL4で自動売買ロボットを注文する方法 MQL5およびMQL4で自動売買ロボットを注文する方法
「フリーランス」は、MQL4/MQL5自動売買ロボットとテクニカルインディケーターを発注できる最大のフリーランスサービスです。何百人ものプロの開発者がいつでもMetaTrader4/5ターミナル用のカスタム取引アプリケーションを開発できます。
MQL5.community - ユーザーメモ MQL5.community - ユーザーメモ
みなさんは登録したばかりで、おそらく「メッセージに写真を挿入する方法は?」、「MQL5 のソースコードをフォーマットする方法は?」、「個人のメッセージはどこに保存されるの?」などという疑問があることでしょう。またそのほかにも数多くの質問があるかもしれません。本稿では MQL5.communityに慣れていただくための実践的な情報を準備し、利用可能な機能を最大限に活用していただけるようにします。
テクニカル分析:何を分析するのか? テクニカル分析:何を分析するのか?
本稿では MetaTrader クライアント端末において利用可能なクオート表示の特殊性をいくつか分析してみます。本稿は一般論を述べるものでプログラムについては述べていません。