MT5とtrans2quik.dll。 - ページ 5 123456789101112...18 新しいコメント prostotrader 2018.12.08 17:34 #41 MT5とQuickの連携は完全に断念し、Quick(DEEサーバー+trans2quik.dll)のみに落ち着きました。 このプログラムの実現を検討しています。 Selector1は常にDDEサーバーからデータを取得し、Storageに「保存」し、対応するChildでOnTick関数を 呼び出します。 GetStorageDataを呼び出すと、DDEサーバーは一時停止し、データはStorageに保存される必要があります。 Selector2がコールバックを呼び出すと、DDEサーバーとストレージの記録が中断され、GetStorageDataの呼び出しが無効になるはずです。 つまり、Selector2が高優先度、GetStorageDataが通常、Selector1が低優先度ということです。 質問です。 Selector1、Selector2、GetStorageDataを優雅に同期させるにはどうしたらよいですか? もしかしたら、そのような同期の具体例があるのかもしれません(私はそのようなものを実装したことがありません)。 Yuriy Asaulenko 2018.12.08 17:45 #42 prostotrader:MT5とQuickの連携を断念し、Quickのみ(DEEサーバ+trans2quik.dll)に落ち着く。 このプログラムの実現を検討しています。1.Quickだけを残したのは、非常に正しい判断だと思います。 2.DEEによる接続は、非常に議論のあるソリューションです。DDEは不安定だと言う人が多いけど、どうなんだろう。 私見では、より良い、より汎用的なソリューションとして、Lua-DLLアプリケーションを使用します。私はこのオプションを使用しています。もちろん、オーナー次第です。 prostotrader 2018.12.08 17:54 #43 Yuriy Asaulenko:1.クイックだけを残すという判断は、正しかったと思う。 2.DDEによる通信は、非常に議論のある決定です。DDEは不安定だと言う人が多いのですが、、、どうなんでしょう。 私見では、より良い、より汎用的なソリューションとして、Lua-DLLアプリケーションを使用します。私はこのオプションを使用しています。もちろん、主催者次第です。昔、Quickquick用のDDEサーバーを書きました。スムーズに動作し、速度も十分です(Lua - DLLより遅くはありません)。 であり、LuaやDDLデータ受信のための追加コードを書く必要は全くありません。 追加 実は、図のようなプログラムをすでに書いて いたのですが(しかも動作する)、同期の問題にぶつかってしまいました。 Yuriy Asaulenko 2018.12.08 18:02 #44 prostotrader:私はずいぶん前にQuick用のDDEサーバーを書きました - スムーズに動作し、十分に速いです(Lua - DLLより遅くはありません)。 であり、Luaで追加のコードを書く必要は全くありません。DDEをやったことがないので、質問ですが、DDEはどのように作られるのですか?データの入ったテーブルを作り、それをDDEで動かすというニーズはあると思います。 イベントとの混同がある。何かが変わったのか、テーブルごとDDEに渡されるようです。それとも私が間違っているのでしょうか? 仮に私が間違っているとしよう。では、受信側でどのように事象を特定すればよいのでしょうか。 プロストトレーダー実は、図にあるようなプログラムをすでに書いて いるのですが(しかも動作する)、同期の問題にぶつかってしまいました。 何と何を同期させるのか? Luaでは、DLLから任意のデータへのコールバックにより、この問題を解決しています。 prostotrader 2018.12.08 18:14 #45 Yuriy Asaulenko:DDEを扱ったことがないので、DDEはどのように作られているのかが問題です。データの入ったテーブルを作り、それをDDEで実行する必要があるようです。 イベントとの混同がある。何かが変わったのか、テーブルごとDDEに渡されるようです。それとも私が間違っているのでしょうか? 仮に私が間違っているとしよう。では、受信側でどのように事象を特定するのか。Quickでは、出力に必要なテーブルが生成されます。 最後に、DDEサーバーで自作アプリケーションを起動し、このテーブルをDDEで出力します。 Quickからの最初の出力では、テーブル全体がDEEに送られ、その後、テーブルの行だけが を変更しました。 テーブル自体には(完全に送信されます)、(例えば私の場合)ツール名 - これが識別子です。 prostotrader 2018.12.08 18:18 #46 DDEサーバー自体は数行です(私はPascalで作っていますが、インターネット上には他の言語での例がたくさんあります)。 unit DdeUnit; interface uses Winapi.Windows, System.Classes, System.Types, Vcl.Forms, Winapi.DdeMl, System.SysUtils, System.StrUtils, Vcl.Controls, Winapi.Messages, QTypes; const WM_DDE_ADDQUE = WM_USER + 2; var ServiceName: string = 'quikdde'; // DDE server name // procedure ClearTable(Table: TDataTable); overload; type TPokeAction = (paAccept, paPass, paReject); TDdePokeEvent = procedure(const Topic: string; var Action: TPokeAction) of object; TDdeDataEvent = procedure(const Topic: string; Cells: TRect; Data: TDataTable) of object; PDdeQueItem = ^TDdeQueItem; TDdeQueItem = packed record data: Pointer; size: integer; sTopic: String; sCells: String; end; TDdeServer = class(TWinControl) private Inst: Integer; ServiceHSz: HSz; TopicHSz: HSz; fOnPoke: TDdePokeEvent; fOnData: TDdeDataEvent; fDdeQue: TThreadList; protected function XLTDecodeV(data: pointer; datasize: integer): TDataTable; function DecodeCellAddr(CellAddr: string): TRect; procedure AddQue(var Message: TWMSysCommand); message WM_DDE_ADDQUE; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; published property OnPoke: TDdePokeEvent read fOnPoke write fOnPoke; property OnData: TDdeDataEvent read fOnData write fOnData; end; //--- Pointer functions ---- function addp(p: Pointer; increment: int64 = 1): Pointer; overload; function addp(p: Pointer; increment: pointer): Pointer; overload; function subp(p: Pointer; decrement: int64 = 1): Pointer; overload; function subp(p: Pointer; decrement: pointer): Pointer; overload; implementation uses main; function CallbackProc(CallType, Fmt: UINT; Conv: HConv; hsz1, hsz2: HSZ; Data: HDDEData; Data1, Data2: DWORD): HDDEData stdcall; var action: TPokeAction; sTopic: String; P: PDdeQueItem; Buff: array[0..255] of WideChar; begin result:= DDE_FNOTPROCESSED; //--- case CallType of XTYP_CONNECT: result:= 1; XTYP_POKE: begin DdeQueryString(QTrader.DdeServer.Inst, HSz1, @Buff, sizeof(Buff), CP_WINUNICODE); sTopic:= string(Buff); action:= paPass; if Assigned(QTrader.DdeServer.fOnPoke) then QTrader.DdeServer.fOnPoke(sTopic, action); //--- case action of paAccept: begin DdeQueryString(QTrader.DdeServer.Inst, HSz2, @Buff, sizeof(Buff), CP_WINUNICODE); New(P); P^.sTopic:= sTopic; P^.sCells:= string(Buff); P^.size:= DdeGetData(Data, nil, 0, 0); GetMem(P^.data, P^.size); DdeGetData(Data, P^.data, P^.size, 0); //--- with QTrader.DdeServer.fDdeQue.LockList do try add(P); finally QTrader.DdeServer.fDdeQue.UnlockList; end; if (QTrader.DdeServer.Handle <> 0) then PostMessage(QTrader.DdeServer.Handle, WM_DDE_ADDQUE, 0, 0); result:= DDE_FACK; end; paPass: result:= DDE_FACK; paReject: result:= DDE_FNOTPROCESSED; end; end; end; end; constructor TDdeServer.Create; begin inherited; fDdeQue := TThreadList.Create; Parent := TWinControl(AOwner); CreateHandle; Inst := 0; if (DdeInitialize(Inst, @CallbackProc, APPCLASS_STANDARD, 0) = DMLERR_NO_ERROR) then begin ServiceHSz := DdeCreateStringHandle(Inst, PWideChar(ServiceName), CP_WINUNICODE); if(DdeNameService(Inst, ServiceHSz, 0, DNS_REGISTER) = 0) then raise Exception.Create( 'Не удалось зарегистрировать имя DDE-сервиса ''' + ServiceName + '''' ); TopicHSz := DdeCreateStringHandle(Inst, PWideChar('Topic'), CP_WINUNICODE); end else raise Exception.Create( 'Не удалось выполнить инициализацию DDE' ); end; destructor TDdeServer.Destroy; begin DdeNameService(Inst, ServiceHsz, 0, DNS_UNREGISTER); fDdeQue.Free; DdeFreeStringHandle(Inst, ServiceHsz); DdeUninitialize(Inst); inherited; end; procedure TDdeServer.AddQue(var Message: TWMSysCommand); var vt: TDataTable; Cells: TRect; p: PDdeQueItem; i: integer; begin with fDdeQue.LockList do try p:= PDdeQueItem(Items[Count - 1]); Cells:= DecodeCellAddr(p^.sCells); vt:= XLTDecodeV(p^.data, p^.size); if (Assigned(QTrader.DdeServer.fOnData)) then QTrader.DdeServer.fOnData(p^.sTopic, Cells, vt); for i:= (Count - 1) downto 0 do begin p:= Items[i]; FreeMem(p^.data, p^.size); Delete(i); Dispose(p); end; finally fDdeQue.UnlockList; end; end; function TDdeServer.XLTDecodeV(data: pointer; datasize: integer): TDataTable; var i: integer; curr: pointer; BlockType: word; BlockSize: word; StringSize: byte; RealData: real; StringData: shortstring; DataNum: integer; begin curr:= addp(data, 4); result.RowCount := Word(curr^); curr:= addp(curr, 2); result.ColCount := Word(curr^); curr:= addp(curr, 2); //--- set array size --- SetLength(result.Cells, result.RowCount); //--- for i := 0 to result.RowCount - 1 do SetLength(result.Cells[i], result.ColCount); //--- data block -------- DataNum := 0; while(Integer(subp(curr, data)) < datasize) do begin BlockType:= Word(curr^); curr:= addp(curr, 2); BlockSize:= Word(curr^); curr:= addp(curr, 2); case BlockType of 1: begin while(BlockSize > 0) do begin RealData:= Real(curr^); curr:= addp(curr, 8); dec(BlockSize, 8); result.Cells[(DataNum div result.ColCount), (DataNum mod result.ColCount)]:= FloatToStr(RealData); inc(DataNum); end; end; 2: begin while(BlockSize > 0) do begin StringSize:= Byte(curr^); curr:= addp( curr ); StringData[0]:= AnsiChar(Chr(StringSize)); //--- for i:= 1 to StringSize do begin StringData[i]:= AnsiChar(Char(curr^)); curr:= addp(curr); end; result.Cells[(DataNum div result.ColCount), (Datanum mod result.ColCount)]:= string(StringData); inc(DataNum); dec(BlockSize, StringSize + 1); end; end; end; end; end; function TDdeServer.DecodeCellAddr( CellAddr: string ): TRect; var tmp1, tmp2: integer; begin CellAddr:= UpperCase(CellAddr); tmp1:= PosEx('R', CellAddr); tmp2:= PosEx('C', CellAddr, tmp1); try result.Top:= StrToInt(copy(CellAddr, tmp1 + 1, tmp2 - tmp1 - 1)) - 1; except exit; end; tmp1:= PosEx('R', CellAddr, tmp2); try Result.Left:= StrToInt(copy(CellAddr, tmp2 + 1, tmp1 - tmp2 - 1 - 1)) - 1; except exit; end; tmp2:= PosEx('C', CellAddr, tmp1); try result.Bottom:= StrToInt(copy(CellAddr, tmp1 + 1, tmp2 - tmp1 - 1)) - 1; result.Right:= StrToInt(copy(CellAddr, tmp2 + 1, Length(CellAddr) - tmp2)) - 1; except exit; end; end; function addp(P: Pointer; increment: int64 = 1): Pointer; overload; begin result:= Pointer(Int64(p) + increment); end; function addp(P: Pointer; increment: Pointer): Pointer; overload; begin result:= Pointer(Int64(p) + Int64(increment)); end; function subp(P: Pointer; decrement: int64 = 1): Pointer; overload; begin result:= Pointer(Int64(p) - decrement); end; function subp(P: Pointer; decrement: Pointer): Pointer; overload; begin result:= Pointer(Int64(p) - Int64(decrement)); end; end. prostotrader 2018.12.08 18:25 #47 ツール名で子ウィンドウが作成される(MT 5と同様) prostotrader 2018.12.08 18:27 #48 Yuriy Asaulenko:何を使って? 図のトピックで問題を説明しました Yuriy Asaulenko 2018.12.08 18:48 #49 prostotrader:図のトピックで問題を説明しましたすみません、気が付きませんでした。私が正しく理解していれば MS SQL Serverなどの DBMSをストレージとして 使用することが解決策になります。これは部分的な解決策かもしれません。 もうひとつは、ラスト・イン、ファースト・アウトのような中間バッファ-・コレクションを使用することである。まあ、それとスレッドの分離ですね。 そうすれば、何も止める必要はなく、すべてがバッファに書き込まれるだけである。まあ、DBMSはマルチユーザーアクセスが可能ですしね。 これだけ適用していますが、パスカルとは6から友達ではありません。 PS PascalからNETのライブラリが使えるそうです。Storageとして 使うには、System.Data、System.Data.Data、System. Data.Data.Dataを使うのが理にかなっているかも しれない。DataSetとSystem.Data.DataTable です。確か、DataTableでは 複数ユーザーによるアクセスは問題なかったはずです。 ZZY2 今、データベースとしてSQLiteを使おうとしていますが、まだはっきりとした結果は出ていません。また、確かにDBMSではありませんが、削ぎ落とした形でマルチユーザーアクセスが可能で、メモリ上にデータベースを作成することもできます。 System.Data Namespace douglaslMSdocs.microsoft.com Пространство имен обеспечивает доступ к классам, представляющим архитектуру ADO.NET. The namespace provides access to classes that represent the ADO.NET architecture. ADO.NET позволяет создавать… prostotrader 2018.12.08 19:25 #50 いや、3つのスレッドを同期させる(基本的にはSynchronizerを書く)だけなんだけどね。 どうしたらいいのかわからない。 123456789101112...18 新しいコメント 取引の機会を逃しています。 無料取引アプリ 8千を超えるシグナルをコピー 金融ニュースで金融マーケットを探索 新規登録 ログイン スペースを含まないラテン文字 このメールにパスワードが送信されます エラーが発生しました Googleでログイン WebサイトポリシーおよびMQL5.COM利用規約に同意します。 新規登録 MQL5.com WebサイトへのログインにCookieの使用を許可します。 ログインするには、ブラウザで必要な設定を有効にしてください。 ログイン/パスワードをお忘れですか? Googleでログイン
MT5とQuickの連携は完全に断念し、Quick(DEEサーバー+trans2quik.dll)のみに落ち着きました。
このプログラムの実現を検討しています。
Selector1は常にDDEサーバーからデータを取得し、Storageに「保存」し、対応するChildでOnTick関数を 呼び出します。
GetStorageDataを呼び出すと、DDEサーバーは一時停止し、データはStorageに保存される必要があります。
Selector2がコールバックを呼び出すと、DDEサーバーとストレージの記録が中断され、GetStorageDataの呼び出しが無効になるはずです。
つまり、Selector2が高優先度、GetStorageDataが通常、Selector1が低優先度ということです。
質問です。
Selector1、Selector2、GetStorageDataを優雅に同期させるにはどうしたらよいですか?
もしかしたら、そのような同期の具体例があるのかもしれません(私はそのようなものを実装したことがありません)。
MT5とQuickの連携を断念し、Quickのみ(DEEサーバ+trans2quik.dll)に落ち着く。
このプログラムの実現を検討しています。
1.Quickだけを残したのは、非常に正しい判断だと思います。
2.DEEによる接続は、非常に議論のあるソリューションです。DDEは不安定だと言う人が多いけど、どうなんだろう。
私見では、より良い、より汎用的なソリューションとして、Lua-DLLアプリケーションを使用します。私はこのオプションを使用しています。もちろん、オーナー次第です。
1.クイックだけを残すという判断は、正しかったと思う。
2.DDEによる通信は、非常に議論のある決定です。DDEは不安定だと言う人が多いのですが、、、どうなんでしょう。
私見では、より良い、より汎用的なソリューションとして、Lua-DLLアプリケーションを使用します。私はこのオプションを使用しています。もちろん、主催者次第です。
昔、Quickquick用のDDEサーバーを書きました。スムーズに動作し、速度も十分です(Lua - DLLより遅くはありません)。
であり、LuaやDDLデータ受信のための追加コードを書く必要は全くありません。
追加
実は、図のようなプログラムをすでに書いて いたのですが(しかも動作する)、同期の問題にぶつかってしまいました。
私はずいぶん前にQuick用のDDEサーバーを書きました - スムーズに動作し、十分に速いです(Lua - DLLより遅くはありません)。
であり、Luaで追加のコードを書く必要は全くありません。
DDEをやったことがないので、質問ですが、DDEはどのように作られるのですか?データの入ったテーブルを作り、それをDDEで動かすというニーズはあると思います。
イベントとの混同がある。何かが変わったのか、テーブルごとDDEに渡されるようです。それとも私が間違っているのでしょうか?
仮に私が間違っているとしよう。では、受信側でどのように事象を特定すればよいのでしょうか。
実は、図にあるようなプログラムをすでに書いて いるのですが(しかも動作する)、同期の問題にぶつかってしまいました。
何と何を同期させるのか?
Luaでは、DLLから任意のデータへのコールバックにより、この問題を解決しています。
DDEを扱ったことがないので、DDEはどのように作られているのかが問題です。データの入ったテーブルを作り、それをDDEで実行する必要があるようです。
イベントとの混同がある。何かが変わったのか、テーブルごとDDEに渡されるようです。それとも私が間違っているのでしょうか?
仮に私が間違っているとしよう。では、受信側でどのように事象を特定するのか。
Quickでは、出力に必要なテーブルが生成されます。
最後に、DDEサーバーで自作アプリケーションを起動し、このテーブルをDDEで出力します。
Quickからの最初の出力では、テーブル全体がDEEに送られ、その後、テーブルの行だけが
を変更しました。
テーブル自体には(完全に送信されます)、(例えば私の場合)ツール名 - これが識別子です。
DDEサーバー自体は数行です(私はPascalで作っていますが、インターネット上には他の言語での例がたくさんあります)。
ツール名で子ウィンドウが作成される(MT 5と同様)
何を使って?
図のトピックで問題を説明しました
図のトピックで問題を説明しました
すみません、気が付きませんでした。私が正しく理解していれば
MS SQL Serverなどの DBMSをストレージとして 使用することが解決策になります。これは部分的な解決策かもしれません。
もうひとつは、ラスト・イン、ファースト・アウトのような中間バッファ-・コレクションを使用することである。まあ、それとスレッドの分離ですね。
そうすれば、何も止める必要はなく、すべてがバッファに書き込まれるだけである。まあ、DBMSはマルチユーザーアクセスが可能ですしね。
これだけ適用していますが、パスカルとは6から友達ではありません。
PS PascalからNETのライブラリが使えるそうです。Storageとして 使うには、System.Data、System.Data.Data、System. Data.Data.Dataを使うのが理にかなっているかも しれない。DataSetとSystem.Data.DataTable です。確か、DataTableでは 複数ユーザーによるアクセスは問題なかったはずです。
ZZY2 今、データベースとしてSQLiteを使おうとしていますが、まだはっきりとした結果は出ていません。また、確かにDBMSではありませんが、削ぎ落とした形でマルチユーザーアクセスが可能で、メモリ上にデータベースを作成することもできます。
いや、3つのスレッドを同期させる(基本的にはSynchronizerを書く)だけなんだけどね。
どうしたらいいのかわからない。