トップページ コミュニティ 質問 関数の実装について

  • 作成者
    スレッド
  • #5817

    shige
    Participant

    お世話になります。

    EA作成講座のRSIをもとに掲示板にありました仕掛け時間を実装したのですが

    関数の返し方がを理解できておらずうまくいきません。

    ご教示いただけましたら助かります。

    内容といたしましては、仕掛け時間がオンならエントリー時間に制限をかける、オフなら時間制限なしといった内容となります。

    ファイル添付できませんでしたので下記にコードを張り付けておきます。

    よろしくお願いいたします。

    //+——————————————————————+

    //| ProjectName |

    //| Copyright 2018, CompanyName |

    //| http://www.companyname.net |

    //+——————————————————————+

    #property copyright “Copyright 2018, MetaQuotes Software Corp.”

    #property link “https://www.mql5.com”

    #property version “1.00”

    #property strict

    input int MAGICMA = 23498721; // マジックナンバー

    input double Lots =0.01; // 1ロット十万通貨単位

    input int LossCut=10 ; // 損切(pips)

    input int TakeProfit = 20; // 利確(pips)

    input int Slippage = 4; // エントリー見送りスリッページ

    input double MaxSpread = 5; // エントリー見送りスプレッド

    input int RSIPeriod=14; // RSI期間

    input int RSIUP = 80; // RSI上の線

    input int RSIDOWN = 20; // RSI下の線

    input bool UseShikake = true;

    input string EntryStartHour2 = “3”;

    input string EntryStartMinute2 = “0”;

    input string EntryEndHour2 = “8”;

    input string EntryEndMinute2 = “0”;

    double dPoint;

    double dSpread;

    //+——————————————————————+

    //| |

    //+——————————————————————+

    int OnInit()

    {

    Print(TimeIfCheck(EntryStartHour2, EntryStartMinute2,EntryEndHour2, EntryEndMinute2));

    dPoint = Point * 10;

    return(INIT_SUCCEEDED);

    }

    //+——————————————————————+

    //| |

    //+——————————————————————+

    void OnTick()

    {

    dSpread = (Ask – Bid) / dPoint;

    if(CalculateCurrentOrders()==0 && dSpread < MaxSpread)

    CheckForOpen();//ポジションを持っていなければポジションを得る

    }

    //+——————————————————————+

    void CheckForOpen()

    {

    int res;

    if(iRSI(Symbol(),0,RSIPeriod,0,0) >= RSIUP && TimeIfCheck() == true )//open[0]が現在のバーの始値

    {

    res=OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, Bid + LossCut * dPoint, Ask – TakeProfit * dPoint, “”, MAGICMA, 0, Red);//戻り値はチケット番号

    if(res < 0)

    Print(“Error OrderSend :”,GetLastError());

    }

    if(iRSI(Symbol(),0,RSIPeriod,0,0) <= RSIDOWN)

    {

    res=OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage, Ask – LossCut * dPoint, Bid + TakeProfit * dPoint,””, MAGICMA, 0, Red);//戻り値はチケット番号

    if(res < 0)

    Print(“Error OrderSend :”,GetLastError());

    }

    }

    //+——————————————————————+

    //| |

    //+——————————————————————+

    int CalculateCurrentOrders()

    {

    int positions = 0;

    //—

    for(int i=0; i<OrdersTotal(); i++)

    {

    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)

    break;

    if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA)

    {

    positions++;

    }

    }

    return positions;

    }

    //+——————————————————————+

    //| |

    //+——————————————————————+

    bool TimeIfCheck(string startTime,string startMinute, string endTime,string endMinute)

    {

    if(!UseShikake)

    return false;

    int iTime_ts = (int)startTime;

    int iTime_ms = (int)startMinute;

    int iTime_te = (int)endTime;

    int iTime_me = (int)endMinute;

    datetime ParTime = TimeCurrent();

    if(iTime_ts < iTime_te || (iTime_ts == iTime_te && iTime_ms <= iTime_me))

    {

    if(TimeHour(ParTime) > iTime_ts || (TimeHour(ParTime) == iTime_ts && TimeMinute(ParTime) >= iTime_ms))

    {

    if(TimeHour(ParTime) < iTime_te || (TimeHour(ParTime) == iTime_te && TimeMinute(ParTime) <= iTime_me))

    {

    return(true);

    }

    }

    }

    else

    {

    if((TimeHour(ParTime) > iTime_ts || (TimeHour(ParTime) == iTime_ts && TimeMinute(ParTime) >= iTime_ms)) || (TimeHour(ParTime) < iTime_te || (TimeHour(ParTime) == iTime_te && TimeMinute(ParTime) <= iTime_me)))

    {

    return(true);

    }

    }

    return(false);

    }

    //+——————————————————————+

  • 関数の実装について

    shige 更新済み 1 月, 3 週間 前 2 メンバー · 13 返信
  • FinTechSchool_Teacher

    管理者
    2023年1月24日 11:55

    CheckForOpen関数の中で、TimeIfCheck関数を呼び出しているかと思いますが、そこで引数の指定が誤っているようですので、4つの引数を指定してください。

    TimeIfCheck(EntryStartHour2, EntryStartMinute2,EntryEndHour2, EntryEndMinute2);

    また、その他具体的にどのようなことがうまくいかないなどありますでしょうか?(意図した時間内なのにtrueじゃなくfalseが帰ってきてしまうなど)

  • shige

    メンバー
    2023年1月25日 07:41

    お世話になります。

    ご教示ありがとうございました。

    下記にように記述したところ、パラメータ設定ででinput bool UseShikake = true;をfalseにしたところエントリーしないようです。falseの場合は時間制限をかけずエントリーするにはどのようにすればよろしいでしょうか?

    また、トレールについてもオン・オフをパラメータで切り替えることはできませんでしょうか?

    関数全般的なところですが、オン・オフを切り替えたいです。エントリー条件としてオフの場合はその条件(関数)をスルーするようなイメージです。

    さらに、関数を作成する際の関数の使い分け、void,bool,int,double,などありますがもう少し詳細に教えていただけましたら幸いです。

    初歩的な質問ばかりで大変申しわけございませんがご教示願えましたらと思います。

    よろしくお願いいたします。

    #property copyright “Copyright 2018, MetaQuotes Software Corp.”

    #property link “https://www.mql5.com”

    #property version “1.00”

    #property strict

    input int MAGICMA = 23498721; // マジックナンバー

    input double Lots =0.01; // 1ロット十万通貨単位

    input int LossCut=10 ; // 損切(pips)

    input int TakeProfit = 40; // 利確(pips)

    input int Slippage = 4; // エントリー見送りスリッページ

    input double MaxSpread = 5; // エントリー見送りスプレッド

    input int TrailWidth = 10; // トレーリング開始pips

    input int RSIPeriod=14; // RSI期間

    input int RSIUP = 80; // RSI上の線

    input int RSIDOWN = 20; // RSI下の線

    input bool UseShikake = true;

    input string EntryStartHour2 = “3”;

    input string EntryStartMinute2 = “0”;

    input string EntryEndHour2 = “8”;

    input string EntryEndMinute2 = “0”;

    double dPoint;

    double dSpread;

    int OnInit()

    {

    dPoint = Point * 10;

    return(INIT_SUCCEEDED);

    }

    void OnTick()

    {

    dSpread = (Ask – Bid) / dPoint;

    if(CalculateCurrentOrders()==0 && dSpread < MaxSpread && TimeIfCheck(EntryStartHour2, EntryStartMinute2, EntryEndHour2, EntryEndMinute2 ) ) CheckForOpen();//ポジションを持っていなければポジションを得る

    TrailingStop();

    ;

    }

    //+——————————————————————+

    void CheckForOpen()

    {

    int res;

    if(iRSI(Symbol(),0,RSIPeriod,0,0) >= RSIUP )//open[0]が現在のバーの始値

    {

    res=OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, Bid + LossCut * dPoint, Ask – TakeProfit * dPoint, “”, MAGICMA, 0, Blue);//戻り値はチケット番号

    if( res < 0 )Print( “Error OrderSend :”,GetLastError() );

    }

    if(iRSI(Symbol(),0,RSIPeriod,0,0) <= RSIDOWN)

    {

    res=OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage, Ask – LossCut * dPoint, Bid + TakeProfit * dPoint,””, MAGICMA, 0, Red);//戻り値はチケット番号

    if( res < 0 )Print( “Error OrderSend :”,GetLastError() );

    }

    }

    int CalculateCurrentOrders()

    {

    int positions = 0;

    //—

    for(int i=0;i<OrdersTotal();i++)

    {

    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;

    if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA)

    {

    positions++;

    }

    }

    return positions;

    }

    void TrailingStop(){

    double stopLoss = 0;

    for(int i = OrdersTotal() – 1; i >= 0; i–){

    if(!(OrderSelect(i, SELECT_BY_POS) == true && OrderMagicNumber() == MAGICMA && OrderSymbol() == Symbol())) continue;

    if(OrderType() == OP_BUY){

    stopLoss = Bid – TrailWidth * dPoint;

    stopLoss = NormalizeDouble(stopLoss, Digits);

    if(stopLoss >= OrderOpenPrice() && (stopLoss > OrderStopLoss()|| OrderStopLoss() == 0)){

    bool res = OrderModify(OrderTicket(), OrderOpenPrice(), stopLoss, OrderTakeProfit(), 0);

    }

    }

    else if(OrderType() == OP_SELL){

    stopLoss = Ask + TrailWidth * dPoint;

    stopLoss = NormalizeDouble(stopLoss, Digits);

    if(stopLoss <= OrderOpenPrice() && (stopLoss < OrderStopLoss() || OrderStopLoss() == 0)){

    bool res = OrderModify(OrderTicket(), OrderOpenPrice(), stopLoss, OrderTakeProfit(), 0);

    }

    }

    }

    }

    bool TimeIfCheck(string startTime,string startMinute, string endTime,string endMinute ){

    if(!UseShikake)return false;

    int iTime_ts = (int)startTime;

    int iTime_ms = (int)startMinute;

    int iTime_te = (int)endTime;

    int iTime_me = (int)endMinute;

    datetime ParTime = TimeCurrent();

    if( iTime_ts < iTime_te || (iTime_ts == iTime_te && iTime_ms <= iTime_me) ){

    if( TimeHour(ParTime) > iTime_ts || (TimeHour(ParTime) == iTime_ts && TimeMinute(ParTime) >= iTime_ms) ){

    if( TimeHour(ParTime) < iTime_te || (TimeHour(ParTime) == iTime_te && TimeMinute(ParTime) <= iTime_me) ){

    return(true);

    }

    }

    }else{

    if( (TimeHour(ParTime) > iTime_ts || (TimeHour(ParTime) == iTime_ts && TimeMinute(ParTime) >= iTime_ms)) || (TimeHour(ParTime) < iTime_te || (TimeHour(ParTime) == iTime_te && TimeMinute(ParTime) <= iTime_me)) ){

    return(true);

    }

    }

    return(false);

    }

    • FinTechSchool_Teacher

      管理者
      2023年1月25日 13:27

      パラメータがoffの場合制限をかけないということですね。

      TimeIfCheckの場合、関数内のはじめを以下のように書き換えて下さい。

      if(!UseShikake)return true;

      こうすることで、パラメータがfalseの場合かならずtrueが関数から返されるため、制限をかけない実装が可能です。

      関数作成時のbool int double void について、これらは関数からの戻り値の型を指定する部分です。

      例えばTimeIfCheck関数は「指定した時間が時間内か時間外か」のtureかfalseを関数から受け取りたいのでboolとなります。

      例えばエントリーの判断を行うCheckForOpen関数は、関数内の計算結果を取得することが目的ではなく、関数内でエントリーを行うことが目的ですので、とくに関数から値を返す必要はなく戻り値の型はvoidとなります。(値を返さない場合void)

      他にも例えば「引数で指定した値の2乗を返す」関数を作成するとして、関数から返す値は数値ですのでdouble型を指定することになります。

      double getNijou(double num){

      return num * num;

      }

  • shige

    メンバー
    2023年1月26日 05:51

    お世話になります。

    上記ご教示ありがとうございます。

    再度ご教示いただきたいのですが、

    bool TimeIfCheck(string startTime,string startMinute, string endTime,string endMinute ){

    if(!UseShikake)return false;

    int iTime_ts = (int)startTime;

    int iTime_ms = (int)startMinute;

    int iTime_te = (int)endTime;

    int iTime_me = (int)endMinute;

    の引数 string startTime,string startMinute, string endTime,string endMinute

    に対して

    TimeIfCheck(EntryStartHour2, EntryStartMinute2, EntryEndHour2, EntryEndMinute2 )

    とすれば稼働いたしますが関数作成時の引数と関数呼び出しの際の引数は異なっていてもよのでしょうか?

    関数作成時

    string startTime,string startMinute, string endTime,string endMinute

    呼び出し時

    パラメータinptの変数

    EntryStartHour2, EntryStartMinute2, EntryEndHour2, EntryEndMinute2

    関数作成時は

    string startTime に対して int iTime_ts = (int)startTime; が代入されているように

    思われますのでこの辺りが混同しており理解に苦しんでおります。

    あと、関数の作成において

    bool TimeIfCheck(string startTime,string startMinute, string endTime,string endMinute ){

    if(!UseShikake)return false;

    int iTime_ts = (int)startTime;

    int iTime_ms = (int)startMinute;

    int iTime_te = (int)endTime;

    int iTime_me = (int)endMinute;

    datetime ParTime = TimeCurrent();

    if( iTime_ts < iTime_te || (iTime_ts == iTime_te && iTime_ms <= iTime_me) ){

    if( TimeHour(ParTime) > iTime_ts || (TimeHour(ParTime) == iTime_ts && TimeMinute(ParTime) >= iTime_ms) ){

    if( TimeHour(ParTime) < iTime_te || (TimeHour(ParTime) == iTime_te && TimeMinute(ParTime) <= iTime_me) ){

    return(true);

    }

    }

    }

    return(false);

    }

    のようにelse部分以下を省略すると弊害がありますでしょうか?

    色々と質問ばかりで申し訳ございませんがご教示いただけましたら助かります。

    よろしくお願いいたします。

  • shige

    メンバー
    2023年1月26日 06:58

    さらに追加のご質問で申し訳ございません。

    疑似エントリーを行い損益比を積み上げていくことは可能でしょうか?

    例えば

    エントリー条件が成立したときにその時の価格を取得 

    その後、ロスカットまたはテイクプロフィット、特定のクローズ条件やトレールによるストップロスに達したときの値を取得し実際にはエントリーせず損益を積み上げていくようなイメージです。

    実際にエントリーした際の損益比は約定時の価格と決済時の価格を取得すればできると思われますが実際のエントリーは行わず疑似エントリーにより損益比を積みあげた値を取得したいです。

    ご教示いただけましたら助かります。

    • FinTechSchool_Teacher

      管理者
      2023年1月26日 12:35

      お世話になっております。

      関数の引数について、呼び出し元と関数の定義の引数名は異なっていて問題ありません。

      例えば

      int returnNum(int num){

      return num;

      }

      という関数を定義した時、呼び出し時は

      retunNum(numA);

      retunNum(3);

      のように異なっていても問題ありません。

      ただし、関数を定義する際に以下のように引数の変数名と異なる変数名は使用することができません。

      int returnNum(int num){

      return numA; //エラーが出る

      }

      else以下について、else以下の機能は開始時間と終了時間が日をまたぐ(24時をまたぐ)際の処理ですので省略すると誤作動を起こすかと思います。

      疑似エントリーについて、グローバル変数などを用いてエントリー時の価格や損益を計算すれば実装可能ですが、スプレッドやスリッページ、エントリータイミングの誤差などにより正確な計算ができずまた実装も複雑なため、デモ口座を新たに開設してEAを動作させることをおすすめいたします。

  • shige

    メンバー
    2023年1月27日 09:24

    お世話になります。

    ご教示ありがとうございます!

    トレールのオン、オフについて実装しようかと思っておりますが下記のような記述でよろしいでしょうか?

    trueならトレールを実行、falseならトレールしないイメージです。

    あと、return true;の場合とreturn( true);

    ( )がつく場合と付かない場合の使い分けについてご教示頂けましたら助かります。

    よろしくお願いいたします。

    inpt bool Trail = true;

    void TrailingStop()
    {
    double stopLoss = 0;

    for(int i = OrdersTotal() – 1; i >= 0; i–)
    {

    if( Trail==true) {if(!Trail)return true;

    if(!(OrderSelect(i, SELECT_BY_POS) == true && OrderMagicNumber() == MAGICMA && OrderSymbol() == Symbol()))
    continue;
    if(OrderType() == OP_BUY)
    {
    stopLoss = Bid – TrailWidth * dPoint;
    stopLoss = NormalizeDouble(stopLoss, Digits);
    if(stopLoss >= OrderOpenPrice() && (stopLoss > OrderStopLoss()|| OrderStopLoss() == 0))
    {
    bool res = OrderModify(OrderTicket(), OrderOpenPrice(), stopLoss, OrderTakeProfit(), 0);
    }
    }
    else
    if(OrderType() == OP_SELL)
    {
    stopLoss = Ask + TrailWidth * dPoint;
    stopLoss = NormalizeDouble(stopLoss, Digits);
    if(stopLoss <= OrderOpenPrice() && (stopLoss < OrderStopLoss() || OrderStopLoss() == 0))
    {
    bool res = OrderModify(OrderTicket(), OrderOpenPrice(), stopLoss, OrderTakeProfit(), 0);
    }
    }
    }
    }inpt bool Trail = true;

    void TrailingStop()
    {
    double stopLoss = 0;
    for(int i = OrdersTotal() – 1; i >= 0; i–)
    {
    if( Trail==true)
    {if(!Trail)return true;
    if(!(OrderSelect(i, SELECT_BY_POS) == true && OrderMagicNumber() == MAGICMA && OrderSymbol() == Symbol()))
    continue;
    if(OrderType() == OP_BUY)
    {
    stopLoss = Bid – TrailWidth * dPoint;
    stopLoss = NormalizeDouble(stopLoss, Digits);
    if(stopLoss >= OrderOpenPrice() && (stopLoss > OrderStopLoss()|| OrderStopLoss() == 0))
    {
    bool res = OrderModify(OrderTicket(), OrderOpenPrice(), stopLoss, OrderTakeProfit(), 0);
    }
    }
    else
    if(OrderType() == OP_SELL)
    {
    stopLoss = Ask + TrailWidth * dPoint;
    stopLoss = NormalizeDouble(stopLoss, Digits);
    if(stopLoss <= OrderOpenPrice() && (stopLoss < OrderStopLoss() || OrderStopLoss() == 0))
    {
    bool res = OrderModify(OrderTicket(), OrderOpenPrice(), stopLoss, OrderTakeProfit(), 0);
    }
    }
    }
    }

  • FinTechSchool_Teacher

    管理者
    2023年1月27日 11:34

    returnの使い方について、かっこの有無は同じ意味ですのでどちらでもかまいません。

    TrailingStopのオンオフについて、inputのtrailでオンオフを実装する際は、関数の中の一番上に

    if(!Trail)return;と記述してください。

    ポイントとしては2つあります。

    1つめは、パラメータtrailはオフの場合トレーリングストップを動作させないため、なるべく早めにif(!Trail)return;を実行したいので関数の一番上に記述してください。(下に書けば書くほど余分な式が実行されてしまいます)

    2つめは、returnのあとにはtrueやfalseが必要ない点です。

    関数は指定した戻り値の値を返す必要がありますが今回の関数はvoid型ですので、何もかえしません。(trueやfalseを返したい場合はこのvoidをboolに変更する必要があります。)

    • shige

      メンバー
      2023年2月2日 07:31

      お世話になります。

      ご教示ありがとうございます。

      多数ロジックを搭載する場合関数の実装についてそれぞれパラメータでオン・オフや数値を変更できるように考えております。

      その場合、各ロジックごとに関数を用意する必要がありますでしょうか?同じ関数を利用し配列などで対応できればと考えていたのですが…

      例えば下記のような例でトレールのオン・オフや数値を各ロジックごとにパラメータで変更したいと思っております。

      //ロジック1トレール

      input bool Trail_buy1 = true;

      void TrailingStop_buy1()

      {

      if(!Trail_buy1)

      return;

      double stopLoss_1 = 0;

      double stopLoss_2 = 0;

      for(int i = OrdersTotal() – 1; i >= 0; i–)

      {

      if(!(OrderSelect(i, SELECT_BY_POS) == true && OrderMagicNumber() == MAGIC_1 && OrderSymbol() == Symbol()))

      continue;

      if(OrderType() == OP_BUY && OrderMagicNumber() == MAGIC_1)

      {

      stopLoss_1 = Bid – TrailWidth_buy1 * dPoint;

      stopLoss_1 = NormalizeDouble(stopLoss_1, Digits);

      stopLoss_2 = Bid – TrailWidth_buy2* dPoint;

      stopLoss_2 = NormalizeDouble(stopLoss_2, Digits);

      if(stopLoss_1 >= OrderOpenPrice() && (stopLoss_2 > OrderStopLoss()|| OrderStopLoss() == 0)

      )

      {

      bool res = OrderModify(OrderTicket(), OrderOpenPrice(), stopLoss_2, OrderTakeProfit(), 0);

      }

      }

      }

      }

      //ロジック2トレール

      input bool Trail_buy2 = true;

      void TrailingStop_buy1()

      {

      if(!Trail_buy2)

      return;

      double stopLoss_1 = 0;

      double stopLoss_2 = 0;

      for(int i = OrdersTotal() – 1; i >= 0; i–)

      {

      if(!(OrderSelect(i, SELECT_BY_POS) == true && OrderMagicNumber() == MAGIC_2 && OrderSymbol() == Symbol()))

      continue;

      if(OrderType() == OP_BUY && OrderMagicNumber() == MAGIC_2)

      {

      stopLoss_1 = Bid – TrailWidth_buy3* dPoint;

      stopLoss_1 = NormalizeDouble(stopLoss_1, Digits);

      stopLoss_2 = Bid – TrailWidth_buy4* dPoint;

      stopLoss_2 = NormalizeDouble(stopLoss_2, Digits);

      if(stopLoss_1 >= OrderOpenPrice() && (stopLoss_2 > OrderStopLoss()|| OrderStopLoss() == 0)

      )

      {

      bool res = OrderModify(OrderTicket(), OrderOpenPrice(), stopLoss_2, OrderTakeProfit(), 0);

      }

      }

      }

      }

      上記のようにロジックごとに記述すると多数各必要性が出るためできるだけコンパクトにしたいと考えております。

      ご教示いただけましたら助かります。

      よろしくお願いいたします。

  • FinTechSchool_Teacher

    管理者
    2023年2月2日 08:01

    お世話になっております。

    関数について、関数はその機能ごとにまとめることで、次回以降EAを作成する際に関数を丸々コピーして流用できるようにというのも重要な考え方です。

    例えば、「ある数字の〇乗を取得する」関数を考えたとき、以下のように2乗、3乗、4乗、、、と書いてしまうと冗長な無駄なプログラムとなってしまいます。

    double get2jou(double num){ return double * double; }

    double get3jou(double num){ return double * double * double; }

    double get4jou(double num){ return double * double * double * double; }

    この場合は、引数で〇乗も指定することで解決します↓

    doubleMarujou(double num, int jou){

    double jouNum = 1;

    for(int i = 0; i < num ; i++){

    jouNum = jouNum * num

    }

    return jouNum;

    }

    トレーリングストップも同様に、TrailingStop1、TraillingStop2のように関数を作成するべきではなく、引数から内部の数字を変更できるようにしてください。例えば、TrailWidth_buy〇などの変数は引数から受け取って使用するとよりスマートになります。

  • shige

    メンバー
    2023年2月2日 14:30

    お世話になります。

    上記ご教示ありがとうございます。

    引数で変数を変えることは理解いたしまた。ただ、トレールのオンオフをパラメータで切り替えるには引数に(bool true ,int TrailWidth1,int TrailWidth2)のような記述でよろしいでしょうか?サイトご教示頂けましたら助かります。よろしくお願いいたします。

  • FinTechSchool_Teacher

    管理者
    2023年2月4日 17:05

    世話になっております。

    そのような記述で問題ありませんが、bool trueの「true」は予約語で変数名には使用することができませんので、「bool useTrail」などの変数名を使用してください。

  • shige

    メンバー
    2023年2月7日 21:26

    色々とご丁寧にご教示頂きありがとうございました。かなり理解が深まりました。

返信にはログインが必要です。

最初の投稿
00 投稿 2018年6月
現在
無料カウンセリングはこちら
無料カウンセリングはこちら